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:
parent
cc9fe2c716
commit
b79018ee3a
|
@ -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))
|
||||
|
|
|
@ -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)];
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue