diff options
author | Corinna Vinschen <corinna@vinschen.de> | 2018-02-07 16:16:51 +0100 |
---|---|---|
committer | Corinna Vinschen <corinna@vinschen.de> | 2018-02-07 16:18:07 +0100 |
commit | c51a0b74dcec39222d5a61189bfe4a6aa73dcf46 (patch) | |
tree | ecba6fb2fd7dd1dac4b6e8e0b2b1dc8d503eb246 | |
parent | 51af517cabcf2677f9ad1b8540dcd98f8e141928 (diff) | |
download | cygnal-c51a0b74dcec39222d5a61189bfe4a6aa73dcf46.tar.gz cygnal-c51a0b74dcec39222d5a61189bfe4a6aa73dcf46.tar.bz2 cygnal-c51a0b74dcec39222d5a61189bfe4a6aa73dcf46.zip |
Cygwin: sockets: Handle SO_RCVTIMEO and SO_SNDTIMEO
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
-rw-r--r-- | winsup/cygwin/fhandler.h | 7 | ||||
-rw-r--r-- | winsup/cygwin/fhandler_socket.cc | 21 | ||||
-rw-r--r-- | winsup/cygwin/net.cc | 42 | ||||
-rw-r--r-- | winsup/cygwin/release/2.10.1 | 13 | ||||
-rw-r--r-- | winsup/cygwin/times.cc | 16 | ||||
-rw-r--r-- | winsup/cygwin/winsup.h | 1 |
6 files changed, 98 insertions, 2 deletions
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 153e3847f..a446e754e 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -524,6 +524,13 @@ class fhandler_socket: public fhandler_base void wmem (int nwmem) { _wmem = nwmem; } private: + DWORD _rcvtimeo; /* msecs */ + DWORD _sndtimeo; /* msecs */ + public: + DWORD &rcvtimeo () { return _rcvtimeo; } + DWORD &sndtimeo () { return _sndtimeo; } + + private: struct _WSAPROTOCOL_INFOW *prot_info_ptr; public: void init_fixup_before (); diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc index 6eac689af..92b4db9f5 100644 --- a/winsup/cygwin/fhandler_socket.cc +++ b/winsup/cygwin/fhandler_socket.cc @@ -227,6 +227,8 @@ fhandler_socket::fhandler_socket () : wsock_events (NULL), wsock_mtx (NULL), wsock_evt (NULL), + _rcvtimeo (INFINITE), + _sndtimeo (INFINITE), prot_info_ptr (NULL), sun_path (NULL), peer_sun_path (NULL), @@ -752,6 +754,8 @@ fhandler_socket::wait_for_events (const long event_mask, const DWORD flags) int ret; long events = 0; + DWORD wfmo_timeout = 50; + DWORD timeout; WSAEVENT ev[3] = { wsock_evt, NULL, NULL }; wait_signal_arrived here (ev[1]); @@ -759,19 +763,32 @@ fhandler_socket::wait_for_events (const long event_mask, const DWORD flags) 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 (is_nonblocking () || (flags & MSG_DONTWAIT)) + if (timeout == 0) { WSASetLastError (WSAEWOULDBLOCK); return SOCKET_ERROR; } - switch (WSAWaitForMultipleEvents (ev_cnt, ev, FALSE, 50, FALSE)) + 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: diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc index 6f96acbd2..43da5dcac 100644 --- a/winsup/cygwin/net.cc +++ b/winsup/cygwin/net.cc @@ -851,6 +851,21 @@ cygwin_setsockopt (int fd, int level, int optname, const void *optval, ignore = true; break; + case SO_RCVTIMEO: + case SO_SNDTIMEO: + if (optlen < (socklen_t) sizeof (struct timeval)) + { + set_errno (EINVAL); + __leave; + } + if (timeval_to_ms ((struct timeval *) optval, + (optname == SO_RCVTIMEO) + ? fh->rcvtimeo () : fh->sndtimeo ())) + res = 0; + else + set_errno (EDOM); + __leave; + default: break; } @@ -999,6 +1014,33 @@ cygwin_getsockopt (int fd, int level, int optname, void *optval, } break; + case SO_RCVTIMEO: + case SO_SNDTIMEO: + { + struct timeval *time_out = (struct timeval *) optval; + + if (*optlen < (socklen_t) sizeof *time_out) + { + set_errno (EINVAL); + __leave; + } + DWORD ms = (optname == SO_RCVTIMEO) ? fh->rcvtimeo () + : fh->sndtimeo (); + if (ms == 0 || ms == INFINITE) + { + time_out->tv_sec = 0; + time_out->tv_usec = 0; + } + else + { + time_out->tv_sec = ms / HZ; + time_out->tv_usec = ((ms % HZ) * USPERSEC) / HZ; + } + *optlen = (socklen_t) sizeof *time_out; + res = 0; + __leave; + } + default: break; } diff --git a/winsup/cygwin/release/2.10.1 b/winsup/cygwin/release/2.10.1 new file mode 100644 index 000000000..f8fd4cb42 --- /dev/null +++ b/winsup/cygwin/release/2.10.1 @@ -0,0 +1,13 @@ +What's new: +----------- + + +What changed: +------------- + +- SO_RCVTIMEO and SO_SNDTIMEO socket options are now honored. + + +Bug Fixes +--------- + diff --git a/winsup/cygwin/times.cc b/winsup/cygwin/times.cc index 86e32b8bf..198fc32ce 100644 --- a/winsup/cygwin/times.cc +++ b/winsup/cygwin/times.cc @@ -216,6 +216,22 @@ timeval_to_filetime (const struct timeval *time_in, PLARGE_INTEGER out) } /* Cygwin internal */ +bool +timeval_to_ms (const struct timeval *time_in, DWORD &ms) +{ + if (time_in->tv_sec < 0 || time_in->tv_usec < 0 + || time_in->tv_usec >= USPERSEC) + return false; + if ((time_in->tv_sec == 0 && time_in->tv_usec == 0) + || time_in->tv_sec >= INFINITE / HZ) + ms = INFINITE; + else + ms = time_in->tv_sec * HZ + (time_in->tv_usec + (USPERSEC/HZ) - 1) + / (USPERSEC/HZ); + return true; +} + +/* Cygwin internal */ static timeval __stdcall time_t_to_timeval (time_t in) { diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h index fcb08e213..1b3fbfeee 100644 --- a/winsup/cygwin/winsup.h +++ b/winsup/cygwin/winsup.h @@ -206,6 +206,7 @@ void __stdcall to_timestruc_t (PLARGE_INTEGER, timestruc_t *); void __stdcall time_as_timestruc_t (timestruc_t *); void __stdcall timeval_to_filetime (const struct timeval *, PLARGE_INTEGER); void __stdcall timespec_to_filetime (const struct timespec *, PLARGE_INTEGER); +bool timeval_to_ms (const struct timeval *, DWORD &); /* Console related */ void __stdcall set_console_title (char *); |