2
0
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:
Christopher Kohlhoff
2010-03-27 10:54:44 +00:00
parent 7efbb6060d
commit d32559c643
2 changed files with 38 additions and 39 deletions

View File

@@ -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;
}

View File

@@ -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;
}