mirror of
https://github.com/boostorg/asio.git
synced 2026-02-25 14:32:08 +00:00
Always call ioctl on underlying descriptor when modifying blocking mode. Refs #3307.
[SVN r60869]
This commit is contained in:
@@ -68,7 +68,7 @@ public:
|
||||
// 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 @@ public:
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -445,43 +445,30 @@ public:
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user