Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r60869 - trunk/boost/asio/detail
From: chris_at_[hidden]
Date: 2010-03-27 06:54:44


Author: chris_kohlhoff
Date: 2010-03-27 06:54:44 EDT (Sat, 27 Mar 2010)
New Revision: 60869
URL: http://svn.boost.org/trac/boost/changeset/60869

Log:
Always call ioctl on underlying descriptor when modifying blocking mode. Refs #3307.

Text files modified:
   trunk/boost/asio/detail/reactive_descriptor_service.hpp | 32 +++++++++++++++++++--------
   trunk/boost/asio/detail/reactive_socket_service.hpp | 45 ++++++++++++++-------------------------
   2 files changed, 38 insertions(+), 39 deletions(-)

Modified: trunk/boost/asio/detail/reactive_descriptor_service.hpp
==============================================================================
--- trunk/boost/asio/detail/reactive_descriptor_service.hpp (original)
+++ trunk/boost/asio/detail/reactive_descriptor_service.hpp 2010-03-27 06:54:44 EDT (Sat, 27 Mar 2010)
@@ -68,7 +68,7 @@
       // The descriptor has been set non-blocking.
       internal_non_blocking = 2,
 
- // Helper "flag" used to determine whether the socket is non-blocking.
+ // Helper "flag" used to determine whether the descriptor is non-blocking.
       non_blocking = user_set_non_blocking | internal_non_blocking
     };
 
@@ -214,19 +214,31 @@
       return ec;
     }
 
- if (command.name() == static_cast<int>(FIONBIO))
+ descriptor_ops::ioctl(impl.descriptor_, command.name(),
+ static_cast<ioctl_arg_type*>(command.data()), ec);
+
+ // When updating the non-blocking mode we always perform the ioctl syscall,
+ // even if the flags would otherwise indicate that the descriptor is
+ // already in the correct state. This ensures that the underlying
+ // descriptor is put into the state that has been requested by the user. If
+ // the ioctl syscall was successful then we need to update the flags to
+ // match.
+ if (!ec && command.name() == static_cast<int>(FIONBIO))
     {
- if (command.get())
+ if (*static_cast<ioctl_arg_type*>(command.data()))
+ {
         impl.flags_ |= implementation_type::user_set_non_blocking;
+ }
       else
- impl.flags_ &= ~implementation_type::user_set_non_blocking;
- ec = boost::system::error_code();
- }
- else
- {
- descriptor_ops::ioctl(impl.descriptor_, command.name(),
- static_cast<ioctl_arg_type*>(command.data()), ec);
+ {
+ // Clearing the non-blocking mode always overrides any internally-set
+ // non-blocking flag. Any subsequent asynchronous operations will need
+ // to re-enable non-blocking I/O.
+ impl.flags_ &= ~(implementation_type::user_set_non_blocking
+ | implementation_type::internal_non_blocking);
+ }
     }
+
     return ec;
   }
 

Modified: trunk/boost/asio/detail/reactive_socket_service.hpp
==============================================================================
--- trunk/boost/asio/detail/reactive_socket_service.hpp (original)
+++ trunk/boost/asio/detail/reactive_socket_service.hpp 2010-03-27 06:54:44 EDT (Sat, 27 Mar 2010)
@@ -445,43 +445,30 @@
       return ec;
     }
 
- if (command.name() == static_cast<int>(FIONBIO))
+ socket_ops::ioctl(impl.socket_, command.name(),
+ static_cast<ioctl_arg_type*>(command.data()), ec);
+
+ // When updating the non-blocking mode we always perform the ioctl
+ // syscall, even if the flags would otherwise indicate that the socket is
+ // already in the correct state. This ensures that the underlying socket
+ // is put into the state that has been requested by the user. If the ioctl
+ // syscall was successful then we need to update the flags to match.
+ if (!ec && command.name() == static_cast<int>(FIONBIO))
     {
- // Flags are manipulated in a temporary variable so that the socket
- // implementation is not updated unless the ioctl operation succeeds.
- unsigned char new_flags = impl.flags_;
       if (*static_cast<ioctl_arg_type*>(command.data()))
- new_flags |= implementation_type::user_set_non_blocking;
- else
- new_flags &= ~implementation_type::user_set_non_blocking;
-
- // Perform ioctl on socket if the non-blocking state has changed.
- if (!(impl.flags_ & implementation_type::non_blocking)
- && (new_flags & implementation_type::non_blocking))
- {
- ioctl_arg_type non_blocking = 1;
- socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec);
- }
- else if ((impl.flags_ & implementation_type::non_blocking)
- && !(new_flags & implementation_type::non_blocking))
       {
- ioctl_arg_type non_blocking = 0;
- socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec);
+ impl.flags_ |= implementation_type::user_set_non_blocking;
       }
       else
       {
- ec = boost::system::error_code();
+ // Clearing the non-blocking mode always overrides any internally-set
+ // non-blocking flag. Any subsequent asynchronous operations will need
+ // to re-enable non-blocking I/O.
+ impl.flags_ &= ~(implementation_type::user_set_non_blocking
+ | implementation_type::internal_non_blocking);
       }
-
- // Update socket implementation's flags only if successful.
- if (!ec)
- impl.flags_ = new_flags;
- }
- else
- {
- socket_ops::ioctl(impl.socket_, command.name(),
- static_cast<ioctl_arg_type*>(command.data()), ec);
     }
+
     return ec;
   }
 


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk