Cygwin: encapsulate Winsock based fhandler_socket classes

Insert another class fhandler_socket_wsock between fhandler_socket
and fhandler_socket_inet/fhandler_socket_local.

Also, add a new method fhandler::is_wsock_socket to allow asking
for sockets in general (is_socket) vs. Winsock-based sockets
(is_wsock_socket).

This allows to develop a new handler_socket_unix class as derived
class from fhandler_socket without any trace of wsock code left
in fhandler_socket.

While this is basically a temporary measure at this time, it may
prove useful for later interoperability with the upcoming Windows 10
AF_UNIX implementation at one point.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
Corinna Vinschen 2018-02-23 15:24:18 +01:00
parent cc9fe2c716
commit b79018ee3a
8 changed files with 711 additions and 1157 deletions

View File

@ -1567,7 +1567,7 @@ fhandler_base::fork_fixup (HANDLE parent, HANDLE &h, const char *name)
{
HANDLE oh = h;
bool res = false;
if (/* !is_socket () && */ !close_on_exec ())
if (!close_on_exec ())
debug_printf ("handle %p already opened", h);
else if (!DuplicateHandle (parent, h, GetCurrentProcess (), &h,
0, !close_on_exec (), DUPLICATE_SAME_ACCESS))

View File

@ -406,6 +406,7 @@ public:
virtual bool isfifo () const { return false; }
virtual int ptsname_r (char *, size_t);
virtual class fhandler_socket *is_socket () { return NULL; }
virtual class fhandler_socket_wsock *is_wsock_socket () { return NULL; }
virtual class fhandler_console *is_console () { return 0; }
virtual int is_windows () {return 0; }
@ -488,7 +489,6 @@ class fhandler_socket: public fhandler_base
protected:
int addr_family;
int type;
virtual int af_local_connect () = 0;
inline int get_socket_flags ()
{
int ret = 0;
@ -499,18 +499,6 @@ class fhandler_socket: public fhandler_base
return ret;
}
protected:
wsa_event *wsock_events;
HANDLE wsock_mtx;
HANDLE wsock_evt;
bool init_events ();
int wait_for_events (const long event_mask, const DWORD flags);
void release_events ();
public:
const HANDLE wsock_event () const { return wsock_evt; }
int evaluate_events (const long event_mask, long &events, const bool erase);
const LONG serial_number () const { return wsock_events->serial_number; }
protected:
int _rmem;
int _wmem;
@ -527,56 +515,30 @@ class fhandler_socket: public fhandler_base
DWORD &rcvtimeo () { return _rcvtimeo; }
DWORD &sndtimeo () { return _sndtimeo; }
protected:
struct _WSAPROTOCOL_INFOW *prot_info_ptr;
protected:
struct status_flags
{
unsigned async_io : 1; /* async I/O */
unsigned saw_shutdown_read : 1; /* Socket saw a SHUT_RD */
unsigned saw_shutdown_write : 1; /* Socket saw a SHUT_WR */
unsigned saw_reuseaddr : 1; /* Socket saw SO_REUSEADDR call */
unsigned connect_state : 3;
unsigned no_getpeereid : 1;
public:
status_flags () :
async_io (0), saw_shutdown_read (0), saw_shutdown_write (0),
connect_state (unconnected), no_getpeereid (0)
connect_state (unconnected)
{}
} status;
#ifdef __INSIDE_CYGWIN_NET__
int set_socket_handle (SOCKET sock, int af, int type, int flags);
#endif
public:
IMPLEMENT_STATUS_FLAG (bool, async_io)
IMPLEMENT_STATUS_FLAG (bool, saw_shutdown_read)
IMPLEMENT_STATUS_FLAG (bool, saw_shutdown_write)
IMPLEMENT_STATUS_FLAG (conn_state, connect_state)
public:
fhandler_socket ();
~fhandler_socket ();
/* Originally get_socket returned an int, which is not a good idea
to cast a handle to on 64 bit. The right type here is very certainly
SOCKET instead. On the other hand, we don't want to have to include
winsock.h just to build fhandler.h. Therefore we define get_socket
now only when building network related code. */
#ifdef __INSIDE_CYGWIN_NET__
SOCKET get_socket () { return (SOCKET) get_handle(); }
#endif
fhandler_socket *is_socket () { return this; }
IMPLEMENT_STATUS_FLAG (bool, async_io)
IMPLEMENT_STATUS_FLAG (bool, saw_shutdown_read)
IMPLEMENT_STATUS_FLAG (bool, saw_shutdown_write)
IMPLEMENT_STATUS_FLAG (bool, saw_reuseaddr)
IMPLEMENT_STATUS_FLAG (conn_state, connect_state)
IMPLEMENT_STATUS_FLAG (bool, no_getpeereid)
bool need_fixup_before () const {return prot_info_ptr != NULL;}
void set_close_on_exec (bool val);
void init_fixup_before ();
int fixup_before_fork_exec (DWORD);
void fixup_after_fork (HANDLE);
void fixup_after_exec ();
int dup (fhandler_base *child, int);
char *get_proc_fd_name (char *buf);
virtual int socket (int af, int type, int protocol, int flags) = 0;
@ -633,14 +595,96 @@ class fhandler_socket: public fhandler_base
virtual select_record *select_except (select_stuff *) = 0;
};
class fhandler_socket_inet: public fhandler_socket
/* Encapsulate wsock-based socket classes fhandler_socket_inet and
fhandler_socket_local during development of fhandler_socket_unix.
TODO: Perhaps we should keep it that way, under the assumption that
the Windows 10 AF_UNIX class will eventually get useful at one point. */
class fhandler_socket_wsock: public fhandler_socket
{
protected:
virtual int af_local_connect () = 0;
protected:
wsa_event *wsock_events;
HANDLE wsock_mtx;
HANDLE wsock_evt;
bool init_events ();
int wait_for_events (const long event_mask, const DWORD flags);
void release_events ();
public:
const HANDLE wsock_event () const { return wsock_evt; }
int evaluate_events (const long event_mask, long &events, const bool erase);
const LONG serial_number () const { return wsock_events->serial_number; }
protected:
struct _WSAPROTOCOL_INFOW *prot_info_ptr;
public:
bool need_fixup_before () const {return prot_info_ptr != NULL;}
void set_close_on_exec (bool val);
void init_fixup_before ();
int fixup_before_fork_exec (DWORD);
void fixup_after_fork (HANDLE);
void fixup_after_exec ();
int dup (fhandler_base *child, int);
#ifdef __INSIDE_CYGWIN_NET__
protected:
int set_socket_handle (SOCKET sock, int af, int type, int flags);
public:
/* Originally get_socket returned an int, which is not a good idea
to cast a handle to on 64 bit. The right type here is very certainly
SOCKET instead. On the other hand, we don't want to have to include
winsock.h just to build fhandler.h. Therefore we define get_socket
now only when building network related code. */
SOCKET get_socket () { return (SOCKET) get_handle(); }
#endif
protected:
struct status_flags
{
unsigned saw_reuseaddr : 1; /* Socket saw SO_REUSEADDR call */
public:
status_flags () : saw_reuseaddr (0) {}
} status;
public:
IMPLEMENT_STATUS_FLAG (bool, saw_reuseaddr)
protected:
virtual ssize_t recv_internal (struct _WSAMSG *wsamsg, bool use_recvmsg) = 0;
ssize_t send_internal (struct _WSAMSG *wsamsg, int flags);
public:
fhandler_socket_wsock ();
~fhandler_socket_wsock ();
fhandler_socket_wsock *is_wsock_socket () { return this; }
ssize_t recvfrom (void *ptr, size_t len, int flags,
struct sockaddr *from, int *fromlen);
ssize_t recvmsg (struct msghdr *msg, int flags);
void __reg3 read (void *ptr, size_t& len);
ssize_t __stdcall readv (const struct iovec *, int iovcnt, ssize_t tot = -1);
ssize_t __stdcall write (const void *ptr, size_t len);
ssize_t __stdcall writev (const struct iovec *, int iovcnt, ssize_t tot = -1);
int shutdown (int how);
int close ();
int ioctl (unsigned int cmd, void *);
int fcntl (int cmd, intptr_t);
/* select.cc */
select_record *select_read (select_stuff *);
select_record *select_write (select_stuff *);
select_record *select_except (select_stuff *);
};
class fhandler_socket_inet: public fhandler_socket_wsock
{
protected:
int af_local_connect () { return 0; }
private:
inline ssize_t recv_internal (struct _WSAMSG *wsamsg, bool use_recvmsg);
inline ssize_t send_internal (struct _WSAMSG *wsamsg, int flags);
protected:
ssize_t recv_internal (struct _WSAMSG *wsamsg, bool use_recvmsg);
public:
fhandler_socket_inet ();
@ -653,31 +697,14 @@ class fhandler_socket_inet: public fhandler_socket
int connect (const struct sockaddr *name, int namelen);
int getsockname (struct sockaddr *name, int *namelen);
int getpeername (struct sockaddr *name, int *namelen);
int shutdown (int how);
int close ();
ssize_t recvfrom (void *ptr, size_t len, int flags,
struct sockaddr *from, int *fromlen);
ssize_t recvmsg (struct msghdr *msg, int flags);
void __reg3 read (void *ptr, size_t& len);
ssize_t __stdcall readv (const struct iovec *, int iovcnt, ssize_t tot = -1);
ssize_t sendto (const void *ptr, size_t len, int flags,
const struct sockaddr *to, int tolen);
ssize_t sendmsg (const struct msghdr *msg, int flags);
ssize_t __stdcall write (const void *ptr, size_t len);
ssize_t __stdcall writev (const struct iovec *, int iovcnt, ssize_t tot = -1);
int setsockopt (int level, int optname, const void *optval,
__socklen_t optlen);
int getsockopt (int level, int optname, const void *optval,
__socklen_t *optlen);
int ioctl (unsigned int cmd, void *);
int fcntl (int cmd, intptr_t);
/* select.cc */
select_record *select_read (select_stuff *);
select_record *select_write (select_stuff *);
select_record *select_except (select_stuff *);
/* from here on: CLONING */
fhandler_socket_inet (void *) {}
@ -697,7 +724,7 @@ class fhandler_socket_inet: public fhandler_socket
}
};
class fhandler_socket_local: public fhandler_socket
class fhandler_socket_local: public fhandler_socket_wsock
{
protected:
char *sun_path;
@ -729,9 +756,18 @@ class fhandler_socket_local: public fhandler_socket
int af_local_set_no_getpeereid ();
void af_local_set_sockpair_cred ();
private:
inline ssize_t recv_internal (struct _WSAMSG *wsamsg, bool use_recvmsg);
inline ssize_t send_internal (struct _WSAMSG *wsamsg, int flags);
protected:
ssize_t recv_internal (struct _WSAMSG *wsamsg, bool use_recvmsg);
protected:
struct status_flags
{
unsigned no_getpeereid : 1;
public:
status_flags () : no_getpeereid (0) {}
} status;
public:
IMPLEMENT_STATUS_FLAG (bool, no_getpeereid)
public:
fhandler_socket_local ();
@ -748,27 +784,15 @@ class fhandler_socket_local: public fhandler_socket
int connect (const struct sockaddr *name, int namelen);
int getsockname (struct sockaddr *name, int *namelen);
int getpeername (struct sockaddr *name, int *namelen);
int shutdown (int how);
int close ();
int getpeereid (pid_t *pid, uid_t *euid, gid_t *egid);
ssize_t recvfrom (void *ptr, size_t len, int flags,
struct sockaddr *from, int *fromlen);
ssize_t recvmsg (struct msghdr *msg, int flags);
void __reg3 read (void *ptr, size_t& len);
ssize_t __stdcall readv (const struct iovec *, int iovcnt, ssize_t tot = -1);
ssize_t sendto (const void *ptr, size_t len, int flags,
const struct sockaddr *to, int tolen);
ssize_t sendmsg (const struct msghdr *msg, int flags);
ssize_t __stdcall write (const void *ptr, size_t len);
ssize_t __stdcall writev (const struct iovec *, int iovcnt, ssize_t tot = -1);
int setsockopt (int level, int optname, const void *optval,
__socklen_t optlen);
int getsockopt (int level, int optname, const void *optval,
__socklen_t *optlen);
int ioctl (unsigned int cmd, void *);
int fcntl (int cmd, intptr_t);
int __reg2 fstat (struct stat *buf);
int __reg2 fstatvfs (struct statvfs *buf);
int __reg1 fchmod (mode_t newmode);
@ -776,11 +800,6 @@ class fhandler_socket_local: public fhandler_socket
int __reg3 facl (int, int, struct acl *);
int __reg2 link (const char *);
/* select.cc */
select_record *select_read (select_stuff *);
select_record *select_write (select_stuff *);
select_record *select_except (select_stuff *);
/* from here on: CLONING */
fhandler_socket_local (void *) {}
@ -2357,7 +2376,6 @@ typedef union
char __pty_master[sizeof (fhandler_pty_master)];
char __registry[sizeof (fhandler_registry)];
char __serial[sizeof (fhandler_serial)];
char __socket[sizeof (fhandler_socket)];
char __socket_inet[sizeof (fhandler_socket_inet)];
char __socket_local[sizeof (fhandler_socket_local)];
char __termios[sizeof (fhandler_termios)];

View File

@ -60,573 +60,14 @@ fhandler_socket::fhandler_socket () :
uid (myself->uid),
gid (myself->gid),
mode (S_IFSOCK | S_IRWXU | S_IRWXG | S_IRWXO),
wsock_events (NULL),
wsock_mtx (NULL),
wsock_evt (NULL),
_rcvtimeo (INFINITE),
_sndtimeo (INFINITE),
prot_info_ptr (NULL),
status ()
{
need_fork_fixup (true);
}
fhandler_socket::~fhandler_socket ()
{
if (prot_info_ptr)
cfree (prot_info_ptr);
}
int
fhandler_socket::set_socket_handle (SOCKET sock, int af, int type, int flags)
{
DWORD hdl_flags;
bool lsp_fixup = false;
/* Usually sockets are inheritable IFS objects. Unfortunately some virus
scanners or other network-oriented software replace normal sockets
with their own kind, which is running through a filter driver called
"layered service provider" (LSP) which, fortunately, are deprecated.
LSP sockets are not kernel objects. They are typically not marked as
inheritable, nor are they IFS handles. They are in fact not inheritable
to child processes, and it does not help to mark them inheritable via
SetHandleInformation. Subsequent socket calls in the child process fail
with error 10038, WSAENOTSOCK.
There's a neat way to workaround these annoying LSP sockets. WSAIoctl
allows to fetch the underlying base socket, which is a normal, inheritable
IFS handle. So we fetch the base socket, duplicate it, and close the
original socket. Now we have a standard IFS socket which (hopefully)
works as expected.
If that doesn't work for some reason, mark the sockets for duplication
via WSADuplicateSocket/WSASocket. This requires to start the child
process in SUSPENDED state so we only do this if really necessary. */
if (!GetHandleInformation ((HANDLE) sock, &hdl_flags)
|| !(hdl_flags & HANDLE_FLAG_INHERIT))
{
int ret;
SOCKET base_sock;
DWORD bret;
lsp_fixup = true;
debug_printf ("LSP handle: %p", sock);
ret = WSAIoctl (sock, SIO_BASE_HANDLE, NULL, 0, (void *) &base_sock,
sizeof (base_sock), &bret, NULL, NULL);
if (ret)
debug_printf ("WSAIoctl: %u", WSAGetLastError ());
else if (base_sock != sock)
{
if (GetHandleInformation ((HANDLE) base_sock, &hdl_flags)
&& (flags & HANDLE_FLAG_INHERIT))
{
if (!DuplicateHandle (GetCurrentProcess (), (HANDLE) base_sock,
GetCurrentProcess (), (PHANDLE) &base_sock,
0, TRUE, DUPLICATE_SAME_ACCESS))
debug_printf ("DuplicateHandle failed, %E");
else
{
::closesocket (sock);
sock = base_sock;
lsp_fixup = false;
}
}
}
}
set_addr_family (af);
set_socket_type (type);
if (flags & SOCK_NONBLOCK)
set_nonblocking (true);
if (flags & SOCK_CLOEXEC)
set_close_on_exec (true);
set_io_handle ((HANDLE) sock);
if (!init_events ())
return -1;
if (lsp_fixup)
init_fixup_before ();
set_flags (O_RDWR | O_BINARY);
set_unique_id ();
if (get_socket_type () == SOCK_DGRAM)
{
/* Workaround the problem that a missing listener on a UDP socket
in a call to sendto will result in select/WSAEnumNetworkEvents
reporting that the socket has pending data and a subsequent call
to recvfrom will return -1 with error set to WSAECONNRESET.
This problem is a regression introduced in Windows 2000.
Instead of fixing the problem, a new socket IOCTL code has
been added, see http://support.microsoft.com/kb/263823 */
BOOL cr = FALSE;
DWORD blen;
if (WSAIoctl (sock, SIO_UDP_CONNRESET, &cr, sizeof cr, NULL, 0,
&blen, NULL, NULL) == SOCKET_ERROR)
debug_printf ("Reset SIO_UDP_CONNRESET: WinSock error %u",
WSAGetLastError ());
}
#ifdef __x86_64__
rmem () = 212992;
wmem () = 212992;
#else
rmem () = 64512;
wmem () = 64512;
#endif
return 0;
}
/* Maximum number of concurrently opened sockets from all Cygwin processes
per session. Note that shared sockets (through dup/fork/exec) are
counted as one socket. */
#define NUM_SOCKS 2048U
#define LOCK_EVENTS \
if (wsock_mtx && \
WaitForSingleObject (wsock_mtx, INFINITE) != WAIT_FAILED) \
{
#define UNLOCK_EVENTS \
ReleaseMutex (wsock_mtx); \
}
static wsa_event wsa_events[NUM_SOCKS] __attribute__((section (".cygwin_dll_common"), shared));
static LONG socket_serial_number __attribute__((section (".cygwin_dll_common"), shared));
static HANDLE wsa_slot_mtx;
static PWCHAR
sock_shared_name (PWCHAR buf, LONG num)
{
__small_swprintf (buf, L"socket.%d", num);
return buf;
}
static wsa_event *
search_wsa_event_slot (LONG new_serial_number)
{
WCHAR name[32], searchname[32];
UNICODE_STRING uname;
OBJECT_ATTRIBUTES attr;
NTSTATUS status;
if (!wsa_slot_mtx)
{
RtlInitUnicodeString (&uname, sock_shared_name (name, 0));
InitializeObjectAttributes (&attr, &uname, OBJ_INHERIT | OBJ_OPENIF,
get_session_parent_dir (),
everyone_sd (CYG_MUTANT_ACCESS));
status = NtCreateMutant (&wsa_slot_mtx, CYG_MUTANT_ACCESS, &attr, FALSE);
if (!NT_SUCCESS (status))
api_fatal ("Couldn't create/open shared socket mutex %S, %y",
&uname, status);
}
switch (WaitForSingleObject (wsa_slot_mtx, INFINITE))
{
case WAIT_OBJECT_0:
case WAIT_ABANDONED:
break;
default:
api_fatal ("WFSO failed for shared socket mutex, %E");
break;
}
unsigned int slot = new_serial_number % NUM_SOCKS;
while (wsa_events[slot].serial_number)
{
HANDLE searchmtx;
RtlInitUnicodeString (&uname, sock_shared_name (searchname,
wsa_events[slot].serial_number));
InitializeObjectAttributes (&attr, &uname, 0, get_session_parent_dir (),
NULL);
status = NtOpenMutant (&searchmtx, READ_CONTROL, &attr);
if (!NT_SUCCESS (status))
break;
/* Mutex still exists, attached socket is active, try next slot. */
NtClose (searchmtx);
slot = (slot + 1) % NUM_SOCKS;
if (slot == (new_serial_number % NUM_SOCKS))
{
/* Did the whole array once. Too bad. */
debug_printf ("No free socket slot");
ReleaseMutex (wsa_slot_mtx);
return NULL;
}
}
memset (&wsa_events[slot], 0, sizeof (wsa_event));
wsa_events[slot].serial_number = new_serial_number;
ReleaseMutex (wsa_slot_mtx);
return wsa_events + slot;
}
bool
fhandler_socket::init_events ()
{
LONG new_serial_number;
WCHAR name[32];
UNICODE_STRING uname;
OBJECT_ATTRIBUTES attr;
NTSTATUS status;
do
{
new_serial_number =
InterlockedIncrement (&socket_serial_number);
if (!new_serial_number) /* 0 is reserved for global mutex */
InterlockedIncrement (&socket_serial_number);
set_ino (new_serial_number);
RtlInitUnicodeString (&uname, sock_shared_name (name, new_serial_number));
InitializeObjectAttributes (&attr, &uname, OBJ_INHERIT | OBJ_OPENIF,
get_session_parent_dir (),
everyone_sd (CYG_MUTANT_ACCESS));
status = NtCreateMutant (&wsock_mtx, CYG_MUTANT_ACCESS, &attr, FALSE);
if (!NT_SUCCESS (status))
{
debug_printf ("NtCreateMutant(%S), %y", &uname, status);
set_errno (ENOBUFS);
return false;
}
if (status == STATUS_OBJECT_NAME_EXISTS)
NtClose (wsock_mtx);
}
while (status == STATUS_OBJECT_NAME_EXISTS);
if ((wsock_evt = CreateEvent (&sec_all, TRUE, FALSE, NULL))
== WSA_INVALID_EVENT)
{
debug_printf ("CreateEvent, %E");
set_errno (ENOBUFS);
NtClose (wsock_mtx);
return false;
}
if (WSAEventSelect (get_socket (), wsock_evt, EVENT_MASK) == SOCKET_ERROR)
{
debug_printf ("WSAEventSelect, %E");
set_winsock_errno ();
NtClose (wsock_evt);
NtClose (wsock_mtx);
return false;
}
if (!(wsock_events = search_wsa_event_slot (new_serial_number)))
{
set_errno (ENOBUFS);
NtClose (wsock_evt);
NtClose (wsock_mtx);
return false;
}
if (get_socket_type () == SOCK_DGRAM)
wsock_events->events = FD_WRITE;
return true;
}
int
fhandler_socket::evaluate_events (const long event_mask, long &events,
const bool erase)
{
int ret = 0;
long events_now = 0;
WSANETWORKEVENTS evts = { 0 };
if (!(WSAEnumNetworkEvents (get_socket (), wsock_evt, &evts)))
{
if (evts.lNetworkEvents)
{
LOCK_EVENTS;
wsock_events->events |= evts.lNetworkEvents;
events_now = (wsock_events->events & event_mask);
if (evts.lNetworkEvents & FD_CONNECT)
{
wsock_events->connect_errorcode = evts.iErrorCode[FD_CONNECT_BIT];
/* Setting the connect_state and calling the AF_LOCAL handshake
here allows to handle this stuff from a single point. This
is independent of FD_CONNECT being requested. Consider a
server calling connect(2) and then immediately poll(2) with
only polling for POLLIN (example: postfix), or select(2) just
asking for descriptors ready to read.
Something weird occurs in Winsock: If you fork off and call
recv/send on the duplicated, already connected socket, another
FD_CONNECT event is generated in the child process. This
would trigger a call to af_local_connect which obviously fail.
Avoid this by calling set_connect_state only if connect_state
is connect_pending. */
if (connect_state () == connect_pending)
{
if (wsock_events->connect_errorcode)
connect_state (connect_failed);
else if (af_local_connect ())
{
wsock_events->connect_errorcode = WSAGetLastError ();
connect_state (connect_failed);
}
else
connect_state (connected);
}
}
UNLOCK_EVENTS;
if ((evts.lNetworkEvents & FD_OOB) && wsock_events->owner)
kill (wsock_events->owner, SIGURG);
}
}
LOCK_EVENTS;
if ((events = events_now) != 0
|| (events = (wsock_events->events & event_mask)) != 0)
{
if (events & FD_CONNECT)
{
int wsa_err = wsock_events->connect_errorcode;
if (wsa_err)
{
/* CV 2014-04-23: This is really weird. If you call connect
asynchronously on a socket and then select, an error like
"Connection refused" is set in the event and in the SO_ERROR
socket option. If you call connect, then dup, then select,
the error is set in the event, but not in the SO_ERROR socket
option, despite the dup'ed socket handle referring to the same
socket. We're trying to workaround this problem here by
taking the connect errorcode from the event and write it back
into the SO_ERROR socket option.
CV 2014-06-16: Call WSASetLastError *after* setsockopt since,
apparently, setsockopt sets the last WSA error code to 0 on
success. */
::setsockopt (get_socket (), SOL_SOCKET, SO_ERROR,
(const char *) &wsa_err, sizeof wsa_err);
WSASetLastError (wsa_err);
ret = SOCKET_ERROR;
}
else
wsock_events->events |= FD_WRITE;
wsock_events->events &= ~FD_CONNECT;
wsock_events->connect_errorcode = 0;
}
/* This test makes accept/connect behave as on Linux when accept/connect
is called on a socket for which shutdown has been called. The second
half of this code is in the shutdown method. */
if (events & FD_CLOSE)
{
if ((event_mask & FD_ACCEPT) && saw_shutdown_read ())
{
WSASetLastError (WSAEINVAL);
ret = SOCKET_ERROR;
}
if (event_mask & FD_CONNECT)
{
WSASetLastError (WSAECONNRESET);
ret = SOCKET_ERROR;
}
}
if (erase)
wsock_events->events &= ~(events & ~(FD_WRITE | FD_CLOSE));
}
UNLOCK_EVENTS;
return ret;
}
int
fhandler_socket::wait_for_events (const long event_mask, const DWORD flags)
{
if (async_io ())
return 0;
int ret;
long events = 0;
DWORD wfmo_timeout = 50;
DWORD timeout;
WSAEVENT ev[3] = { wsock_evt, NULL, NULL };
wait_signal_arrived here (ev[1]);
DWORD ev_cnt = 2;
if ((ev[2] = pthread::get_cancel_event ()) != NULL)
++ev_cnt;
if (is_nonblocking () || (flags & MSG_DONTWAIT))
timeout = 0;
else if (event_mask & FD_READ)
timeout = rcvtimeo ();
else if (event_mask & FD_WRITE)
timeout = sndtimeo ();
else
timeout = INFINITE;
while (!(ret = evaluate_events (event_mask, events, !(flags & MSG_PEEK)))
&& !events)
{
if (timeout == 0)
{
WSASetLastError (WSAEWOULDBLOCK);
return SOCKET_ERROR;
}
if (timeout < wfmo_timeout)
wfmo_timeout = timeout;
switch (WSAWaitForMultipleEvents (ev_cnt, ev, FALSE, wfmo_timeout, FALSE))
{
case WSA_WAIT_TIMEOUT:
case WSA_WAIT_EVENT_0:
if (timeout != INFINITE)
timeout -= wfmo_timeout;
break;
case WSA_WAIT_EVENT_0 + 1:
if (_my_tls.call_signal_handler ())
break;
WSASetLastError (WSAEINTR);
return SOCKET_ERROR;
case WSA_WAIT_EVENT_0 + 2:
pthread::static_cancel_self ();
break;
default:
/* wsock_evt can be NULL. We're generating the same errno values
as for sockets on which shutdown has been called. */
if (WSAGetLastError () != WSA_INVALID_HANDLE)
WSASetLastError (WSAEFAULT);
else
WSASetLastError ((event_mask & FD_CONNECT) ? WSAECONNRESET
: WSAEINVAL);
return SOCKET_ERROR;
}
}
return ret;
}
void
fhandler_socket::release_events ()
{
if (WaitForSingleObject (wsock_mtx, INFINITE) != WAIT_FAILED)
{
HANDLE evt = wsock_evt;
HANDLE mtx = wsock_mtx;
wsock_evt = wsock_mtx = NULL;
ReleaseMutex (mtx);
NtClose (evt);
NtClose (mtx);
}
}
void
fhandler_socket::set_close_on_exec (bool val)
{
set_no_inheritance (wsock_mtx, val);
set_no_inheritance (wsock_evt, val);
if (need_fixup_before ())
{
close_on_exec (val);
debug_printf ("set close_on_exec for %s to %d", get_name (), val);
}
else
fhandler_base::set_close_on_exec (val);
}
/* Called if a freshly created socket is not inheritable. In that case we
have to use fixup_before_fork_exec. See comment in set_socket_handle for
a description of the problem. */
void
fhandler_socket::init_fixup_before ()
{
prot_info_ptr = (LPWSAPROTOCOL_INFOW)
cmalloc_abort (HEAP_BUF, sizeof (WSAPROTOCOL_INFOW));
cygheap->fdtab.inc_need_fixup_before ();
}
int
fhandler_socket::fixup_before_fork_exec (DWORD win_pid)
{
SOCKET ret = WSADuplicateSocketW (get_socket (), win_pid, prot_info_ptr);
if (ret)
set_winsock_errno ();
else
debug_printf ("WSADuplicateSocket succeeded (%x)", prot_info_ptr->dwProviderReserved);
return (int) ret;
}
void
fhandler_socket::fixup_after_fork (HANDLE parent)
{
fork_fixup (parent, wsock_mtx, "wsock_mtx");
fork_fixup (parent, wsock_evt, "wsock_evt");
if (!need_fixup_before ())
{
fhandler_base::fixup_after_fork (parent);
return;
}
SOCKET new_sock = WSASocketW (FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO, prot_info_ptr, 0,
WSA_FLAG_OVERLAPPED);
if (new_sock == INVALID_SOCKET)
{
set_winsock_errno ();
set_io_handle ((HANDLE) INVALID_SOCKET);
}
else
{
/* Even though the original socket was not inheritable, the duplicated
socket is potentially inheritable again. */
SetHandleInformation ((HANDLE) new_sock, HANDLE_FLAG_INHERIT, 0);
set_io_handle ((HANDLE) new_sock);
debug_printf ("WSASocket succeeded (%p)", new_sock);
}
}
void
fhandler_socket::fixup_after_exec ()
{
if (need_fixup_before () && !close_on_exec ())
fixup_after_fork (NULL);
}
int
fhandler_socket::dup (fhandler_base *child, int flags)
{
debug_printf ("here");
fhandler_socket *fhs = (fhandler_socket *) child;
if (!DuplicateHandle (GetCurrentProcess (), wsock_mtx,
GetCurrentProcess (), &fhs->wsock_mtx,
0, TRUE, DUPLICATE_SAME_ACCESS))
{
__seterrno ();
return -1;
}
if (!DuplicateHandle (GetCurrentProcess (), wsock_evt,
GetCurrentProcess (), &fhs->wsock_evt,
0, TRUE, DUPLICATE_SAME_ACCESS))
{
__seterrno ();
NtClose (fhs->wsock_mtx);
return -1;
}
if (!need_fixup_before ())
{
int ret = fhandler_base::dup (child, flags);
if (ret)
{
NtClose (fhs->wsock_evt);
NtClose (fhs->wsock_mtx);
}
return ret;
}
cygheap->user.deimpersonate ();
fhs->init_fixup_before ();
fhs->set_io_handle (get_io_handle ());
int ret = fhs->fixup_before_fork_exec (GetCurrentProcessId ());
cygheap->user.reimpersonate ();
if (!ret)
{
fhs->fixup_after_fork (GetCurrentProcess ());
if (fhs->get_io_handle() != (HANDLE) INVALID_SOCKET)
return 0;
}
cygheap->fdtab.dec_need_fixup_before ();
NtClose (fhs->wsock_evt);
NtClose (fhs->wsock_mtx);
return -1;
}
char *

View File

@ -59,6 +59,89 @@
ReleaseMutex (wsock_mtx); \
}
/* Maximum number of concurrently opened sockets from all Cygwin processes
per session. Note that shared sockets (through dup/fork/exec) are
counted as one socket. */
#define NUM_SOCKS 2048U
#define LOCK_EVENTS \
if (wsock_mtx && \
WaitForSingleObject (wsock_mtx, INFINITE) != WAIT_FAILED) \
{
#define UNLOCK_EVENTS \
ReleaseMutex (wsock_mtx); \
}
static wsa_event wsa_events[NUM_SOCKS] __attribute__((section (".cygwin_dll_common"), shared));
static LONG socket_serial_number __attribute__((section (".cygwin_dll_common"), shared));
static HANDLE wsa_slot_mtx;
static PWCHAR
sock_shared_name (PWCHAR buf, LONG num)
{
__small_swprintf (buf, L"socket.%d", num);
return buf;
}
static wsa_event *
search_wsa_event_slot (LONG new_serial_number)
{
WCHAR name[32], searchname[32];
UNICODE_STRING uname;
OBJECT_ATTRIBUTES attr;
NTSTATUS status;
if (!wsa_slot_mtx)
{
RtlInitUnicodeString (&uname, sock_shared_name (name, 0));
InitializeObjectAttributes (&attr, &uname, OBJ_INHERIT | OBJ_OPENIF,
get_session_parent_dir (),
everyone_sd (CYG_MUTANT_ACCESS));
status = NtCreateMutant (&wsa_slot_mtx, CYG_MUTANT_ACCESS, &attr, FALSE);
if (!NT_SUCCESS (status))
api_fatal ("Couldn't create/open shared socket mutex %S, %y",
&uname, status);
}
switch (WaitForSingleObject (wsa_slot_mtx, INFINITE))
{
case WAIT_OBJECT_0:
case WAIT_ABANDONED:
break;
default:
api_fatal ("WFSO failed for shared socket mutex, %E");
break;
}
unsigned int slot = new_serial_number % NUM_SOCKS;
while (wsa_events[slot].serial_number)
{
HANDLE searchmtx;
RtlInitUnicodeString (&uname, sock_shared_name (searchname,
wsa_events[slot].serial_number));
InitializeObjectAttributes (&attr, &uname, 0, get_session_parent_dir (),
NULL);
status = NtOpenMutant (&searchmtx, READ_CONTROL, &attr);
if (!NT_SUCCESS (status))
break;
/* Mutex still exists, attached socket is active, try next slot. */
NtClose (searchmtx);
slot = (slot + 1) % NUM_SOCKS;
if (slot == (new_serial_number % NUM_SOCKS))
{
/* Did the whole array once. Too bad. */
debug_printf ("No free socket slot");
ReleaseMutex (wsa_slot_mtx);
return NULL;
}
}
memset (&wsa_events[slot], 0, sizeof (wsa_event));
wsa_events[slot].serial_number = new_serial_number;
ReleaseMutex (wsa_slot_mtx);
return wsa_events + slot;
}
/* cygwin internal: map sockaddr into internet domain address */
static int
get_inet_addr_inet (const struct sockaddr *in, int inlen,
@ -123,8 +206,496 @@ convert_ws1_ip_optname (int optname)
: ws2_optname[optname];
}
fhandler_socket_wsock::fhandler_socket_wsock () :
fhandler_socket (),
wsock_events (NULL),
wsock_mtx (NULL),
wsock_evt (NULL),
prot_info_ptr (NULL),
status ()
{
need_fork_fixup (true);
}
fhandler_socket_wsock::~fhandler_socket_wsock ()
{
if (prot_info_ptr)
cfree (prot_info_ptr);
}
bool
fhandler_socket_wsock::init_events ()
{
LONG new_serial_number;
WCHAR name[32];
UNICODE_STRING uname;
OBJECT_ATTRIBUTES attr;
NTSTATUS status;
do
{
new_serial_number =
InterlockedIncrement (&socket_serial_number);
if (!new_serial_number) /* 0 is reserved for global mutex */
InterlockedIncrement (&socket_serial_number);
set_ino (new_serial_number);
RtlInitUnicodeString (&uname, sock_shared_name (name, new_serial_number));
InitializeObjectAttributes (&attr, &uname, OBJ_INHERIT | OBJ_OPENIF,
get_session_parent_dir (),
everyone_sd (CYG_MUTANT_ACCESS));
status = NtCreateMutant (&wsock_mtx, CYG_MUTANT_ACCESS, &attr, FALSE);
if (!NT_SUCCESS (status))
{
debug_printf ("NtCreateMutant(%S), %y", &uname, status);
set_errno (ENOBUFS);
return false;
}
if (status == STATUS_OBJECT_NAME_EXISTS)
NtClose (wsock_mtx);
}
while (status == STATUS_OBJECT_NAME_EXISTS);
if ((wsock_evt = CreateEvent (&sec_all, TRUE, FALSE, NULL))
== WSA_INVALID_EVENT)
{
debug_printf ("CreateEvent, %E");
set_errno (ENOBUFS);
NtClose (wsock_mtx);
return false;
}
if (WSAEventSelect (get_socket (), wsock_evt, EVENT_MASK) == SOCKET_ERROR)
{
debug_printf ("WSAEventSelect, %E");
set_winsock_errno ();
NtClose (wsock_evt);
NtClose (wsock_mtx);
return false;
}
if (!(wsock_events = search_wsa_event_slot (new_serial_number)))
{
set_errno (ENOBUFS);
NtClose (wsock_evt);
NtClose (wsock_mtx);
return false;
}
if (get_socket_type () == SOCK_DGRAM)
wsock_events->events = FD_WRITE;
return true;
}
int
fhandler_socket_wsock::evaluate_events (const long event_mask, long &events,
const bool erase)
{
int ret = 0;
long events_now = 0;
WSANETWORKEVENTS evts = { 0 };
if (!(WSAEnumNetworkEvents (get_socket (), wsock_evt, &evts)))
{
if (evts.lNetworkEvents)
{
LOCK_EVENTS;
wsock_events->events |= evts.lNetworkEvents;
events_now = (wsock_events->events & event_mask);
if (evts.lNetworkEvents & FD_CONNECT)
{
wsock_events->connect_errorcode = evts.iErrorCode[FD_CONNECT_BIT];
/* Setting the connect_state and calling the AF_LOCAL handshake
here allows to handle this stuff from a single point. This
is independent of FD_CONNECT being requested. Consider a
server calling connect(2) and then immediately poll(2) with
only polling for POLLIN (example: postfix), or select(2) just
asking for descriptors ready to read.
Something weird occurs in Winsock: If you fork off and call
recv/send on the duplicated, already connected socket, another
FD_CONNECT event is generated in the child process. This
would trigger a call to af_local_connect which obviously fail.
Avoid this by calling set_connect_state only if connect_state
is connect_pending. */
if (connect_state () == connect_pending)
{
if (wsock_events->connect_errorcode)
connect_state (connect_failed);
else if (af_local_connect ())
{
wsock_events->connect_errorcode = WSAGetLastError ();
connect_state (connect_failed);
}
else
connect_state (connected);
}
}
UNLOCK_EVENTS;
if ((evts.lNetworkEvents & FD_OOB) && wsock_events->owner)
kill (wsock_events->owner, SIGURG);
}
}
LOCK_EVENTS;
if ((events = events_now) != 0
|| (events = (wsock_events->events & event_mask)) != 0)
{
if (events & FD_CONNECT)
{
int wsa_err = wsock_events->connect_errorcode;
if (wsa_err)
{
/* CV 2014-04-23: This is really weird. If you call connect
asynchronously on a socket and then select, an error like
"Connection refused" is set in the event and in the SO_ERROR
socket option. If you call connect, then dup, then select,
the error is set in the event, but not in the SO_ERROR socket
option, despite the dup'ed socket handle referring to the same
socket. We're trying to workaround this problem here by
taking the connect errorcode from the event and write it back
into the SO_ERROR socket option.
CV 2014-06-16: Call WSASetLastError *after* setsockopt since,
apparently, setsockopt sets the last WSA error code to 0 on
success. */
::setsockopt (get_socket (), SOL_SOCKET, SO_ERROR,
(const char *) &wsa_err, sizeof wsa_err);
WSASetLastError (wsa_err);
ret = SOCKET_ERROR;
}
else
wsock_events->events |= FD_WRITE;
wsock_events->events &= ~FD_CONNECT;
wsock_events->connect_errorcode = 0;
}
/* This test makes accept/connect behave as on Linux when accept/connect
is called on a socket for which shutdown has been called. The second
half of this code is in the shutdown method. */
if (events & FD_CLOSE)
{
if ((event_mask & FD_ACCEPT) && saw_shutdown_read ())
{
WSASetLastError (WSAEINVAL);
ret = SOCKET_ERROR;
}
if (event_mask & FD_CONNECT)
{
WSASetLastError (WSAECONNRESET);
ret = SOCKET_ERROR;
}
}
if (erase)
wsock_events->events &= ~(events & ~(FD_WRITE | FD_CLOSE));
}
UNLOCK_EVENTS;
return ret;
}
int
fhandler_socket_wsock::wait_for_events (const long event_mask,
const DWORD flags)
{
if (async_io ())
return 0;
int ret;
long events = 0;
DWORD wfmo_timeout = 50;
DWORD timeout;
WSAEVENT ev[3] = { wsock_evt, NULL, NULL };
wait_signal_arrived here (ev[1]);
DWORD ev_cnt = 2;
if ((ev[2] = pthread::get_cancel_event ()) != NULL)
++ev_cnt;
if (is_nonblocking () || (flags & MSG_DONTWAIT))
timeout = 0;
else if (event_mask & FD_READ)
timeout = rcvtimeo ();
else if (event_mask & FD_WRITE)
timeout = sndtimeo ();
else
timeout = INFINITE;
while (!(ret = evaluate_events (event_mask, events, !(flags & MSG_PEEK)))
&& !events)
{
if (timeout == 0)
{
WSASetLastError (WSAEWOULDBLOCK);
return SOCKET_ERROR;
}
if (timeout < wfmo_timeout)
wfmo_timeout = timeout;
switch (WSAWaitForMultipleEvents (ev_cnt, ev, FALSE, wfmo_timeout, FALSE))
{
case WSA_WAIT_TIMEOUT:
case WSA_WAIT_EVENT_0:
if (timeout != INFINITE)
timeout -= wfmo_timeout;
break;
case WSA_WAIT_EVENT_0 + 1:
if (_my_tls.call_signal_handler ())
break;
WSASetLastError (WSAEINTR);
return SOCKET_ERROR;
case WSA_WAIT_EVENT_0 + 2:
pthread::static_cancel_self ();
break;
default:
/* wsock_evt can be NULL. We're generating the same errno values
as for sockets on which shutdown has been called. */
if (WSAGetLastError () != WSA_INVALID_HANDLE)
WSASetLastError (WSAEFAULT);
else
WSASetLastError ((event_mask & FD_CONNECT) ? WSAECONNRESET
: WSAEINVAL);
return SOCKET_ERROR;
}
}
return ret;
}
void
fhandler_socket_wsock::release_events ()
{
if (WaitForSingleObject (wsock_mtx, INFINITE) != WAIT_FAILED)
{
HANDLE evt = wsock_evt;
HANDLE mtx = wsock_mtx;
wsock_evt = wsock_mtx = NULL;
ReleaseMutex (mtx);
NtClose (evt);
NtClose (mtx);
}
}
void
fhandler_socket_wsock::set_close_on_exec (bool val)
{
set_no_inheritance (wsock_mtx, val);
set_no_inheritance (wsock_evt, val);
if (need_fixup_before ())
{
close_on_exec (val);
debug_printf ("set close_on_exec for %s to %d", get_name (), val);
}
else
fhandler_base::set_close_on_exec (val);
}
/* Called if a freshly created socket is not inheritable. In that case we
have to use fixup_before_fork_exec. See comment in set_socket_handle for
a description of the problem. */
void
fhandler_socket_wsock::init_fixup_before ()
{
prot_info_ptr = (LPWSAPROTOCOL_INFOW)
cmalloc_abort (HEAP_BUF, sizeof (WSAPROTOCOL_INFOW));
cygheap->fdtab.inc_need_fixup_before ();
}
int
fhandler_socket_wsock::fixup_before_fork_exec (DWORD win_pid)
{
SOCKET ret = WSADuplicateSocketW (get_socket (), win_pid, prot_info_ptr);
if (ret)
set_winsock_errno ();
else
debug_printf ("WSADuplicateSocket succeeded (%x)", prot_info_ptr->dwProviderReserved);
return (int) ret;
}
void
fhandler_socket_wsock::fixup_after_fork (HANDLE parent)
{
fork_fixup (parent, wsock_mtx, "wsock_mtx");
fork_fixup (parent, wsock_evt, "wsock_evt");
if (!need_fixup_before ())
{
fhandler_base::fixup_after_fork (parent);
return;
}
SOCKET new_sock = WSASocketW (FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO, prot_info_ptr, 0,
WSA_FLAG_OVERLAPPED);
if (new_sock == INVALID_SOCKET)
{
set_winsock_errno ();
set_io_handle ((HANDLE) INVALID_SOCKET);
}
else
{
/* Even though the original socket was not inheritable, the duplicated
socket is potentially inheritable again. */
SetHandleInformation ((HANDLE) new_sock, HANDLE_FLAG_INHERIT, 0);
set_io_handle ((HANDLE) new_sock);
debug_printf ("WSASocket succeeded (%p)", new_sock);
}
}
void
fhandler_socket_wsock::fixup_after_exec ()
{
if (need_fixup_before () && !close_on_exec ())
fixup_after_fork (NULL);
}
int
fhandler_socket_wsock::dup (fhandler_base *child, int flags)
{
debug_printf ("here");
fhandler_socket_wsock *fhs = (fhandler_socket_wsock *) child;
if (!DuplicateHandle (GetCurrentProcess (), wsock_mtx,
GetCurrentProcess (), &fhs->wsock_mtx,
0, TRUE, DUPLICATE_SAME_ACCESS))
{
__seterrno ();
return -1;
}
if (!DuplicateHandle (GetCurrentProcess (), wsock_evt,
GetCurrentProcess (), &fhs->wsock_evt,
0, TRUE, DUPLICATE_SAME_ACCESS))
{
__seterrno ();
NtClose (fhs->wsock_mtx);
return -1;
}
if (!need_fixup_before ())
{
int ret = fhandler_base::dup (child, flags);
if (ret)
{
NtClose (fhs->wsock_evt);
NtClose (fhs->wsock_mtx);
}
return ret;
}
cygheap->user.deimpersonate ();
fhs->init_fixup_before ();
fhs->set_io_handle (get_io_handle ());
int ret = fhs->fixup_before_fork_exec (GetCurrentProcessId ());
cygheap->user.reimpersonate ();
if (!ret)
{
fhs->fixup_after_fork (GetCurrentProcess ());
if (fhs->get_io_handle() != (HANDLE) INVALID_SOCKET)
return 0;
}
cygheap->fdtab.dec_need_fixup_before ();
NtClose (fhs->wsock_evt);
NtClose (fhs->wsock_mtx);
return -1;
}
int
fhandler_socket_wsock::set_socket_handle (SOCKET sock, int af, int type,
int flags)
{
DWORD hdl_flags;
bool lsp_fixup = false;
/* Usually sockets are inheritable IFS objects. Unfortunately some virus
scanners or other network-oriented software replace normal sockets
with their own kind, which is running through a filter driver called
"layered service provider" (LSP) which, fortunately, are deprecated.
LSP sockets are not kernel objects. They are typically not marked as
inheritable, nor are they IFS handles. They are in fact not inheritable
to child processes, and it does not help to mark them inheritable via
SetHandleInformation. Subsequent socket calls in the child process fail
with error 10038, WSAENOTSOCK.
There's a neat way to workaround these annoying LSP sockets. WSAIoctl
allows to fetch the underlying base socket, which is a normal, inheritable
IFS handle. So we fetch the base socket, duplicate it, and close the
original socket. Now we have a standard IFS socket which (hopefully)
works as expected.
If that doesn't work for some reason, mark the sockets for duplication
via WSADuplicateSocket/WSASocket. This requires to start the child
process in SUSPENDED state so we only do this if really necessary. */
if (!GetHandleInformation ((HANDLE) sock, &hdl_flags)
|| !(hdl_flags & HANDLE_FLAG_INHERIT))
{
int ret;
SOCKET base_sock;
DWORD bret;
lsp_fixup = true;
debug_printf ("LSP handle: %p", sock);
ret = WSAIoctl (sock, SIO_BASE_HANDLE, NULL, 0, (void *) &base_sock,
sizeof (base_sock), &bret, NULL, NULL);
if (ret)
debug_printf ("WSAIoctl: %u", WSAGetLastError ());
else if (base_sock != sock)
{
if (GetHandleInformation ((HANDLE) base_sock, &hdl_flags)
&& (flags & HANDLE_FLAG_INHERIT))
{
if (!DuplicateHandle (GetCurrentProcess (), (HANDLE) base_sock,
GetCurrentProcess (), (PHANDLE) &base_sock,
0, TRUE, DUPLICATE_SAME_ACCESS))
debug_printf ("DuplicateHandle failed, %E");
else
{
::closesocket (sock);
sock = base_sock;
lsp_fixup = false;
}
}
}
}
set_addr_family (af);
set_socket_type (type);
if (flags & SOCK_NONBLOCK)
set_nonblocking (true);
if (flags & SOCK_CLOEXEC)
set_close_on_exec (true);
set_io_handle ((HANDLE) sock);
if (!init_events ())
return -1;
if (lsp_fixup)
init_fixup_before ();
set_flags (O_RDWR | O_BINARY);
set_unique_id ();
if (get_socket_type () == SOCK_DGRAM)
{
/* Workaround the problem that a missing listener on a UDP socket
in a call to sendto will result in select/WSAEnumNetworkEvents
reporting that the socket has pending data and a subsequent call
to recvfrom will return -1 with error set to WSAECONNRESET.
This problem is a regression introduced in Windows 2000.
Instead of fixing the problem, a new socket IOCTL code has
been added, see http://support.microsoft.com/kb/263823 */
BOOL cr = FALSE;
DWORD blen;
if (WSAIoctl (sock, SIO_UDP_CONNRESET, &cr, sizeof cr, NULL, 0,
&blen, NULL, NULL) == SOCKET_ERROR)
debug_printf ("Reset SIO_UDP_CONNRESET: WinSock error %u",
WSAGetLastError ());
}
#ifdef __x86_64__
rmem () = 212992;
wmem () = 212992;
#else
rmem () = 64512;
wmem () = 64512;
#endif
return 0;
}
fhandler_socket_inet::fhandler_socket_inet () :
fhandler_socket ()
fhandler_socket_wsock ()
{
}
@ -398,7 +969,7 @@ fhandler_socket_inet::getpeername (struct sockaddr *name, int *namelen)
}
int
fhandler_socket_inet::shutdown (int how)
fhandler_socket_wsock::shutdown (int how)
{
int res = ::shutdown (get_socket (), how);
@ -437,7 +1008,7 @@ fhandler_socket_inet::shutdown (int how)
}
int
fhandler_socket_inet::close ()
fhandler_socket_wsock::close ()
{
int res = 0;
@ -458,12 +1029,10 @@ fhandler_socket_inet::close ()
}
WSASetLastError (0);
}
debug_printf ("%d = fhandler_socket::close()", res);
return res;
}
inline ssize_t
ssize_t
fhandler_socket_inet::recv_internal (LPWSAMSG wsamsg, bool use_recvmsg)
{
ssize_t res = 0;
@ -594,8 +1163,8 @@ fhandler_socket_inet::recv_internal (LPWSAMSG wsamsg, bool use_recvmsg)
}
ssize_t
fhandler_socket_inet::recvfrom (void *in_ptr, size_t len, int flags,
struct sockaddr *from, int *fromlen)
fhandler_socket_wsock::recvfrom (void *in_ptr, size_t len, int flags,
struct sockaddr *from, int *fromlen)
{
char *ptr = (char *) in_ptr;
@ -630,7 +1199,7 @@ fhandler_socket_inet::recvfrom (void *in_ptr, size_t len, int flags,
}
ssize_t
fhandler_socket_inet::recvmsg (struct msghdr *msg, int flags)
fhandler_socket_wsock::recvmsg (struct msghdr *msg, int flags)
{
/* Disappointing but true: Even if WSARecvMsg is supported, it's only
supported for datagram and raw sockets. */
@ -665,7 +1234,7 @@ fhandler_socket_inet::recvmsg (struct msghdr *msg, int flags)
}
void __reg3
fhandler_socket_inet::read (void *in_ptr, size_t& len)
fhandler_socket_wsock::read (void *in_ptr, size_t& len)
{
char *ptr = (char *) in_ptr;
@ -692,8 +1261,8 @@ fhandler_socket_inet::read (void *in_ptr, size_t& len)
}
ssize_t
fhandler_socket_inet::readv (const struct iovec *const iov, const int iovcnt,
ssize_t tot)
fhandler_socket_wsock::readv (const struct iovec *const iov, const int iovcnt,
ssize_t tot)
{
WSABUF wsabuf[iovcnt];
WSABUF *wsaptr = wsabuf + iovcnt;
@ -707,8 +1276,8 @@ fhandler_socket_inet::readv (const struct iovec *const iov, const int iovcnt,
return recv_internal (&wsamsg, false);
}
inline ssize_t
fhandler_socket_inet::send_internal (struct _WSAMSG *wsamsg, int flags)
ssize_t
fhandler_socket_wsock::send_internal (struct _WSAMSG *wsamsg, int flags)
{
ssize_t res = 0;
DWORD ret = 0, sum = 0;
@ -891,7 +1460,7 @@ fhandler_socket_inet::sendmsg (const struct msghdr *msg, int flags)
}
ssize_t
fhandler_socket_inet::write (const void *in_ptr, size_t len)
fhandler_socket_wsock::write (const void *in_ptr, size_t len)
{
char *ptr = (char *) in_ptr;
@ -917,8 +1486,8 @@ fhandler_socket_inet::write (const void *in_ptr, size_t len)
}
ssize_t
fhandler_socket_inet::writev (const struct iovec *const iov, const int iovcnt,
ssize_t tot)
fhandler_socket_wsock::writev (const struct iovec *const iov, const int iovcnt,
ssize_t tot)
{
WSABUF wsabuf[iovcnt];
WSABUF *wsaptr = wsabuf;
@ -1219,7 +1788,7 @@ fhandler_socket_inet::getsockopt (int level, int optname, const void *optval,
}
int
fhandler_socket_inet::ioctl (unsigned int cmd, void *p)
fhandler_socket_wsock::ioctl (unsigned int cmd, void *p)
{
int res;
@ -1287,7 +1856,7 @@ fhandler_socket_inet::ioctl (unsigned int cmd, void *p)
}
int
fhandler_socket_inet::fcntl (int cmd, intptr_t arg)
fhandler_socket_wsock::fcntl (int cmd, intptr_t arg)
{
int res = 0;

View File

@ -221,9 +221,10 @@ get_ext_funcptr (SOCKET sock, void *funcptr)
}
fhandler_socket_local::fhandler_socket_local () :
fhandler_socket (),
fhandler_socket_wsock (),
sun_path (NULL),
peer_sun_path (NULL)
peer_sun_path (NULL),
status ()
{
}
@ -1044,73 +1045,7 @@ fhandler_socket_local::getpeername (struct sockaddr *name, int *namelen)
return res;
}
int
fhandler_socket_local::shutdown (int how)
{
int res = ::shutdown (get_socket (), how);
/* Linux allows to call shutdown for any socket, even if it's not connected.
This also disables to call accept on this socket, if shutdown has been
called with the SHUT_RD or SHUT_RDWR parameter. In contrast, WinSock
only allows to call shutdown on a connected socket. The accept function
is in no way affected. So, what we do here is to fake success, and to
change the event settings so that an FD_CLOSE event is triggered for the
calling Cygwin function. The evaluate_events method handles the call
from accept specially to generate a Linux-compatible behaviour. */
if (res && WSAGetLastError () != WSAENOTCONN)
set_winsock_errno ();
else
{
res = 0;
switch (how)
{
case SHUT_RD:
saw_shutdown_read (true);
wsock_events->events |= FD_CLOSE;
SetEvent (wsock_evt);
break;
case SHUT_WR:
saw_shutdown_write (true);
break;
case SHUT_RDWR:
saw_shutdown_read (true);
saw_shutdown_write (true);
wsock_events->events |= FD_CLOSE;
SetEvent (wsock_evt);
break;
}
}
return res;
}
int
fhandler_socket_local::close ()
{
int res = 0;
release_events ();
while ((res = ::closesocket (get_socket ())) != 0)
{
if (WSAGetLastError () != WSAEWOULDBLOCK)
{
set_winsock_errno ();
res = -1;
break;
}
if (cygwait (10) == WAIT_SIGNALED)
{
set_errno (EINTR);
res = -1;
break;
}
WSASetLastError (0);
}
debug_printf ("%d = fhandler_socket::close()", res);
return res;
}
inline ssize_t
ssize_t
fhandler_socket_local::recv_internal (LPWSAMSG wsamsg, bool use_recvmsg)
{
ssize_t res = 0;
@ -1279,235 +1214,6 @@ fhandler_socket_local::recv_internal (LPWSAMSG wsamsg, bool use_recvmsg)
return ret;
}
ssize_t
fhandler_socket_local::recvfrom (void *in_ptr, size_t len, int flags,
struct sockaddr *from, int *fromlen)
{
char *ptr = (char *) in_ptr;
#ifdef __x86_64__
/* size_t is 64 bit, but the len member in WSABUF is 32 bit.
Split buffer if necessary. */
DWORD bufcnt = len / UINT32_MAX + ((!len || (len % UINT32_MAX)) ? 1 : 0);
WSABUF wsabuf[bufcnt];
WSAMSG wsamsg = { from, from && fromlen ? *fromlen : 0,
wsabuf, bufcnt,
{ 0, NULL },
(DWORD) flags };
/* Don't use len as loop condition, it could be 0. */
for (WSABUF *wsaptr = wsabuf; bufcnt--; ++wsaptr)
{
wsaptr->len = MIN (len, UINT32_MAX);
wsaptr->buf = ptr;
len -= wsaptr->len;
ptr += wsaptr->len;
}
#else
WSABUF wsabuf = { len, ptr };
WSAMSG wsamsg = { from, from && fromlen ? *fromlen : 0,
&wsabuf, 1,
{ 0, NULL},
(DWORD) flags };
#endif
ssize_t ret = recv_internal (&wsamsg, false);
if (fromlen)
*fromlen = wsamsg.namelen;
return ret;
}
ssize_t
fhandler_socket_local::recvmsg (struct msghdr *msg, int flags)
{
/* TODO: Descriptor passing on AF_LOCAL sockets. */
/* Disappointing but true: Even if WSARecvMsg is supported, it's only
supported for datagram and raw sockets. */
bool use_recvmsg = true;
if (get_socket_type () == SOCK_STREAM || get_addr_family () == AF_LOCAL)
{
use_recvmsg = false;
msg->msg_controllen = 0;
}
WSABUF wsabuf[msg->msg_iovlen];
WSABUF *wsaptr = wsabuf + msg->msg_iovlen;
const struct iovec *iovptr = msg->msg_iov + msg->msg_iovlen;
while (--wsaptr >= wsabuf)
{
wsaptr->len = (--iovptr)->iov_len;
wsaptr->buf = (char *) iovptr->iov_base;
}
WSAMSG wsamsg = { (struct sockaddr *) msg->msg_name, msg->msg_namelen,
wsabuf, (DWORD) msg->msg_iovlen,
{ (DWORD) msg->msg_controllen, (char *) msg->msg_control },
(DWORD) flags };
ssize_t ret = recv_internal (&wsamsg, use_recvmsg);
if (ret >= 0)
{
msg->msg_namelen = wsamsg.namelen;
msg->msg_controllen = wsamsg.Control.len;
if (!CYGWIN_VERSION_CHECK_FOR_USING_ANCIENT_MSGHDR)
msg->msg_flags = wsamsg.dwFlags;
}
return ret;
}
void __reg3
fhandler_socket_local::read (void *in_ptr, size_t& len)
{
char *ptr = (char *) in_ptr;
#ifdef __x86_64__
/* size_t is 64 bit, but the len member in WSABUF is 32 bit.
Split buffer if necessary. */
DWORD bufcnt = len / UINT32_MAX + ((!len || (len % UINT32_MAX)) ? 1 : 0);
WSABUF wsabuf[bufcnt];
WSAMSG wsamsg = { NULL, 0, wsabuf, bufcnt, { 0, NULL }, 0 };
/* Don't use len as loop condition, it could be 0. */
for (WSABUF *wsaptr = wsabuf; bufcnt--; ++wsaptr)
{
wsaptr->len = MIN (len, UINT32_MAX);
wsaptr->buf = ptr;
len -= wsaptr->len;
ptr += wsaptr->len;
}
#else
WSABUF wsabuf = { len, ptr };
WSAMSG wsamsg = { NULL, 0, &wsabuf, 1, { 0, NULL }, 0 };
#endif
len = recv_internal (&wsamsg, false);
}
ssize_t
fhandler_socket_local::readv (const struct iovec *const iov, const int iovcnt,
ssize_t tot)
{
WSABUF wsabuf[iovcnt];
WSABUF *wsaptr = wsabuf + iovcnt;
const struct iovec *iovptr = iov + iovcnt;
while (--wsaptr >= wsabuf)
{
wsaptr->len = (--iovptr)->iov_len;
wsaptr->buf = (char *) iovptr->iov_base;
}
WSAMSG wsamsg = { NULL, 0, wsabuf, (DWORD) iovcnt, { 0, NULL}, 0 };
return recv_internal (&wsamsg, false);
}
inline ssize_t
fhandler_socket_local::send_internal (struct _WSAMSG *wsamsg, int flags)
{
ssize_t res = 0;
DWORD ret = 0, sum = 0;
WSABUF out_buf[wsamsg->dwBufferCount];
bool use_sendmsg = false;
DWORD wait_flags = flags & MSG_DONTWAIT;
bool nosignal = !!(flags & MSG_NOSIGNAL);
flags &= (MSG_OOB | MSG_DONTROUTE);
if (wsamsg->Control.len > 0)
use_sendmsg = true;
/* Workaround for MSDN KB 823764: Split a message into chunks <= SO_SNDBUF.
in_idx is the index of the current lpBuffers from the input wsamsg buffer.
in_off is used to keep track of the next byte to write from a wsamsg
buffer which only gets partially written. */
for (DWORD in_idx = 0, in_off = 0;
in_idx < wsamsg->dwBufferCount;
in_off >= wsamsg->lpBuffers[in_idx].len && (++in_idx, in_off = 0))
{
/* Split a message into the least number of pieces to minimize the
number of WsaSendTo calls. Don't split datagram messages (bad idea).
out_idx is the index of the next buffer in the out_buf WSABUF,
also the number of buffers given to WSASendTo.
out_len is the number of bytes in the buffers given to WSASendTo.
Don't split datagram messages (very bad idea). */
DWORD out_idx = 0;
DWORD out_len = 0;
if (get_socket_type () == SOCK_STREAM)
{
do
{
out_buf[out_idx].buf = wsamsg->lpBuffers[in_idx].buf + in_off;
out_buf[out_idx].len = wsamsg->lpBuffers[in_idx].len - in_off;
out_len += out_buf[out_idx].len;
out_idx++;
}
while (out_len < (unsigned) wmem ()
&& (in_off = 0, ++in_idx < wsamsg->dwBufferCount));
/* Tweak len of the last out_buf buffer so the entire number of bytes
is (less than or) equal to wmem (). Fix out_len as well since it's
used in a subsequent test expression. */
if (out_len > (unsigned) wmem ())
{
out_buf[out_idx - 1].len -= out_len - (unsigned) wmem ();
out_len = (unsigned) wmem ();
}
/* Add the bytes written from the current last buffer to in_off,
so in_off points to the next byte to be written from that buffer,
or beyond which lets the outper loop skip to the next buffer. */
in_off += out_buf[out_idx - 1].len;
}
do
{
if (use_sendmsg)
res = WSASendMsg (get_socket (), wsamsg, flags, &ret, NULL, NULL);
else if (get_socket_type () == SOCK_STREAM)
res = WSASendTo (get_socket (), out_buf, out_idx, &ret, flags,
wsamsg->name, wsamsg->namelen, NULL, NULL);
else
res = WSASendTo (get_socket (), wsamsg->lpBuffers,
wsamsg->dwBufferCount, &ret, flags,
wsamsg->name, wsamsg->namelen, NULL, NULL);
if (res && (WSAGetLastError () == WSAEWOULDBLOCK))
{
LOCK_EVENTS;
wsock_events->events &= ~FD_WRITE;
UNLOCK_EVENTS;
}
}
while (res && (WSAGetLastError () == WSAEWOULDBLOCK)
&& !(res = wait_for_events (FD_WRITE | FD_CLOSE, wait_flags)));
if (!res)
{
sum += ret;
/* For streams, return to application if the number of bytes written
is less than the number of bytes we intended to write in a single
call to WSASendTo. Otherwise we would have to add code to
backtrack in the input buffers, which is questionable. There was
probably a good reason we couldn't write more. */
if (get_socket_type () != SOCK_STREAM || ret < out_len)
break;
}
else if (is_nonblocking () || WSAGetLastError() != WSAEWOULDBLOCK)
break;
}
if (sum)
res = sum;
else if (res == SOCKET_ERROR)
{
set_winsock_errno ();
/* Special handling for EPIPE and SIGPIPE.
EPIPE is generated if the local end has been shut down on a connection
oriented socket. In this case the process will also receive a SIGPIPE
unless MSG_NOSIGNAL is set. */
if ((get_errno () == ECONNABORTED || get_errno () == ESHUTDOWN)
&& get_socket_type () == SOCK_STREAM)
{
set_errno (EPIPE);
if (!nosignal)
raise (SIGPIPE);
}
}
return res;
}
ssize_t
fhandler_socket_local::sendto (const void *in_ptr, size_t len, int flags,
const struct sockaddr *to, int tolen)
@ -1578,48 +1284,6 @@ fhandler_socket_local::sendmsg (const struct msghdr *msg, int flags)
return send_internal (&wsamsg, flags);
}
ssize_t
fhandler_socket_local::write (const void *in_ptr, size_t len)
{
char *ptr = (char *) in_ptr;
#ifdef __x86_64__
/* size_t is 64 bit, but the len member in WSABUF is 32 bit.
Split buffer if necessary. */
DWORD bufcnt = len / UINT32_MAX + ((!len || (len % UINT32_MAX)) ? 1 : 0);
WSABUF wsabuf[bufcnt];
WSAMSG wsamsg = { NULL, 0, wsabuf, bufcnt, { 0, NULL }, 0 };
/* Don't use len as loop condition, it could be 0. */
for (WSABUF *wsaptr = wsabuf; bufcnt--; ++wsaptr)
{
wsaptr->len = MIN (len, UINT32_MAX);
wsaptr->buf = ptr;
len -= wsaptr->len;
ptr += wsaptr->len;
}
#else
WSABUF wsabuf = { len, ptr };
WSAMSG wsamsg = { NULL, 0, &wsabuf, 1, { 0, NULL }, 0 };
#endif
return send_internal (&wsamsg, 0);
}
ssize_t
fhandler_socket_local::writev (const struct iovec *const iov, const int iovcnt,
ssize_t tot)
{
WSABUF wsabuf[iovcnt];
WSABUF *wsaptr = wsabuf;
const struct iovec *iovptr = iov;
for (int i = 0; i < iovcnt; ++i)
{
wsaptr->len = iovptr->iov_len;
(wsaptr++)->buf = (char *) (iovptr++)->iov_base;
}
WSAMSG wsamsg = { NULL, 0, wsabuf, (DWORD) iovcnt, { 0, NULL}, 0 };
return send_internal (&wsamsg, 0);
}
void
fhandler_socket_local::set_sun_path (const char *path)
{
@ -1907,86 +1571,3 @@ fhandler_socket_local::getsockopt (int level, int optname, const void *optval,
return ret;
}
int
fhandler_socket_local::ioctl (unsigned int cmd, void *p)
{
int res;
switch (cmd)
{
/* FIXME: These have to be handled differently in future. */
case FIOASYNC:
#ifdef __x86_64__
case _IOW('f', 125, u_long):
#endif
res = WSAAsyncSelect (get_socket (), winmsg, WM_ASYNCIO,
*(int *) p ? ASYNC_MASK : 0);
syscall_printf ("Async I/O on socket %s",
*(int *) p ? "started" : "cancelled");
async_io (*(int *) p != 0);
/* If async_io is switched off, revert the event handling. */
if (*(int *) p == 0)
WSAEventSelect (get_socket (), wsock_evt, EVENT_MASK);
break;
case FIONREAD:
#ifdef __x86_64__
case _IOR('f', 127, u_long):
#endif
/* Make sure to use the Winsock definition of FIONREAD. */
res = ::ioctlsocket (get_socket (), _IOR('f', 127, u_long), (u_long *) p);
if (res == SOCKET_ERROR)
set_winsock_errno ();
break;
case FIONBIO:
case SIOCATMARK:
/* Sockets are always non-blocking internally. So we just note the
state here. */
#ifdef __x86_64__
/* Convert the different idea of u_long in the definition of cmd. */
if (((cmd >> 16) & IOCPARM_MASK) == sizeof (unsigned long))
cmd = (cmd & ~(IOCPARM_MASK << 16)) | (sizeof (u_long) << 16);
#endif
if (cmd == FIONBIO)
{
syscall_printf ("socket is now %sblocking",
*(int *) p ? "non" : "");
set_nonblocking (*(int *) p);
res = 0;
}
else
res = ::ioctlsocket (get_socket (), cmd, (u_long *) p);
break;
default:
res = fhandler_socket::ioctl (cmd, p);
break;
}
syscall_printf ("%d = ioctl_socket(%x, %p)", res, cmd, p);
return res;
}
int
fhandler_socket_local::fcntl (int cmd, intptr_t arg)
{
int res = 0;
switch (cmd)
{
case F_SETOWN:
{
pid_t pid = (pid_t) arg;
LOCK_EVENTS;
wsock_events->owner = pid;
UNLOCK_EVENTS;
debug_printf ("owner set to %d", pid);
}
break;
case F_GETOWN:
res = wsock_events->owner;
break;
default:
res = fhandler_socket::fcntl (cmd, arg);
break;
}
return res;
}

View File

@ -1384,8 +1384,7 @@ cygwin_getpeername (int fd, struct sockaddr *name, socklen_t *len)
}
__except (EFAULT) {}
__endtry
syscall_printf ("%R = getpeername(%d) %p", res, fd,
(fh ? fh->get_socket () : (SOCKET) -1));
syscall_printf ("%R = getpeername(%d)", res, fd);
return res;
}

View File

@ -94,12 +94,12 @@ poll (struct pollfd *fds, nfds_t nfds, int timeout)
{
if (fds[i].fd >= 0 && fds[i].revents != POLLNVAL)
{
fhandler_socket *sock;
fhandler_socket_wsock *sock;
/* Check if the descriptor has been closed, or if shutdown for the
read side has been called on a socket. */
if (cygheap->fdtab.not_open (fds[i].fd)
|| ((sock = cygheap->fdtab[fds[i].fd]->is_socket ())
|| ((sock = cygheap->fdtab[fds[i].fd]->is_wsock_socket ())
&& sock->saw_shutdown_read ()))
fds[i].revents = POLLHUP;
else
@ -117,7 +117,7 @@ poll (struct pollfd *fds, nfds_t nfds, int timeout)
/* Handle failed connect. A failed connect implicitly sets
POLLOUT, if requested, but it doesn't set POLLIN. */
if ((fds[i].events & POLLIN)
&& (sock = cygheap->fdtab[fds[i].fd]->is_socket ())
&& (sock = cygheap->fdtab[fds[i].fd]->is_wsock_socket ())
&& sock->connect_state () == connect_failed)
fds[i].revents |= (POLLIN | POLLERR);
else

View File

@ -501,7 +501,7 @@ set_bits (select_record *me, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds)
{
int ready = 0;
fhandler_socket *sock;
fhandler_socket_wsock *sock;
select_printf ("me %p, testing fd %d (%s)", me, me->fd, me->fh->get_name ());
if (me->read_selected && me->read_ready)
{
@ -511,7 +511,7 @@ set_bits (select_record *me, fd_set *readfds, fd_set *writefds,
if (me->write_selected && me->write_ready)
{
UNIX_FD_SET (me->fd, writefds);
if (me->except_on_write && (sock = me->fh->is_socket ()))
if (me->except_on_write && (sock = me->fh->is_wsock_socket ()))
{
/* Set readfds entry in case of a failed connect. */
if (!me->read_ready && me->read_selected
@ -1364,7 +1364,7 @@ fhandler_base::select_except (select_stuff *ss)
static int
peek_socket (select_record *me, bool)
{
fhandler_socket *fh = (fhandler_socket *) me->fh;
fhandler_socket_wsock *fh = (fhandler_socket_wsock *) me->fh;
long events;
/* Don't play with the settings again, unless having taken a deep look into
Richard W. Stevens Network Programming book. Thank you. */
@ -1488,7 +1488,7 @@ start_thread_socket (select_record *me, select_stuff *stuff)
/* No event/socket should show up multiple times. Every socket
is uniquely identified by its serial number in the global
wsock_events record. */
const LONG ser_num = ((fhandler_socket *) s->fh)->serial_number ();
const LONG ser_num = ((fhandler_socket_wsock *) s->fh)->serial_number ();
for (int i = 1; i < si->num_w4; ++i)
if (si->ser_num[i] == ser_num)
goto continue_outer_loop;
@ -1517,7 +1517,7 @@ start_thread_socket (select_record *me, select_stuff *stuff)
_my_tls.locals.select.max_w4 += MAXIMUM_WAIT_OBJECTS;
}
si->ser_num[si->num_w4] = ser_num;
si->w4[si->num_w4++] = ((fhandler_socket *) s->fh)->wsock_event ();
si->w4[si->num_w4++] = ((fhandler_socket_wsock *) s->fh)->wsock_event ();
continue_outer_loop:
;
}
@ -1549,7 +1549,7 @@ socket_cleanup (select_record *, select_stuff *stuff)
}
select_record *
fhandler_socket_inet::select_read (select_stuff *ss)
fhandler_socket_wsock::select_read (select_stuff *ss)
{
select_record *s = ss->start.next;
if (!s->startup)
@ -1565,7 +1565,7 @@ fhandler_socket_inet::select_read (select_stuff *ss)
}
select_record *
fhandler_socket_inet::select_write (select_stuff *ss)
fhandler_socket_wsock::select_write (select_stuff *ss)
{
select_record *s = ss->start.next;
if (!s->startup)
@ -1586,61 +1586,7 @@ fhandler_socket_inet::select_write (select_stuff *ss)
}
select_record *
fhandler_socket_inet::select_except (select_stuff *ss)
{
select_record *s = ss->start.next;
if (!s->startup)
{
s->startup = start_thread_socket;
s->verify = verify_true;
s->cleanup = socket_cleanup;
}
s->peek = peek_socket;
/* FIXME: Is this right? Should these be used as criteria for except? */
s->except_ready = saw_shutdown_write () || saw_shutdown_read ();
s->except_selected = true;
return s;
}
select_record *
fhandler_socket_local::select_read (select_stuff *ss)
{
select_record *s = ss->start.next;
if (!s->startup)
{
s->startup = start_thread_socket;
s->verify = verify_true;
s->cleanup = socket_cleanup;
}
s->peek = peek_socket;
s->read_ready = saw_shutdown_read ();
s->read_selected = true;
return s;
}
select_record *
fhandler_socket_local::select_write (select_stuff *ss)
{
select_record *s = ss->start.next;
if (!s->startup)
{
s->startup = start_thread_socket;
s->verify = verify_true;
s->cleanup = socket_cleanup;
}
s->peek = peek_socket;
s->write_ready = saw_shutdown_write () || connect_state () == unconnected;
s->write_selected = true;
if (connect_state () != unconnected)
{
s->except_ready = saw_shutdown_write () || saw_shutdown_read ();
s->except_on_write = true;
}
return s;
}
select_record *
fhandler_socket_local::select_except (select_stuff *ss)
fhandler_socket_wsock::select_except (select_stuff *ss)
{
select_record *s = ss->start.next;
if (!s->startup)