This is the mail archive of the
cygwin-cvs@cygwin.com
mailing list for the Cygwin project.
[newlib-cygwin] Cygwin: sockets: Handle SO_RCVTIMEO and SO_SNDTIMEO
- From: Corinna Vinschen <corinna at sourceware dot org>
- To: cygwin-cvs at sourceware dot org
- Date: 7 Feb 2018 15:18:44 -0000
- Subject: [newlib-cygwin] Cygwin: sockets: Handle SO_RCVTIMEO and SO_SNDTIMEO
https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=c51a0b74dcec39222d5a61189bfe4a6aa73dcf46
commit c51a0b74dcec39222d5a61189bfe4a6aa73dcf46
Author: Corinna Vinschen <corinna@vinschen.de>
Date: Wed Feb 7 16:16:51 2018 +0100
Cygwin: sockets: Handle SO_RCVTIMEO and SO_SNDTIMEO
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Diff:
---
winsup/cygwin/fhandler.h | 7 +++++++
winsup/cygwin/fhandler_socket.cc | 21 ++++++++++++++++++--
winsup/cygwin/net.cc | 42 ++++++++++++++++++++++++++++++++++++++++
winsup/cygwin/release/2.10.1 | 13 +++++++++++++
winsup/cygwin/times.cc | 16 +++++++++++++++
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 153e384..a446e75 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 6eac689..92b4db9 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 6f96acb..43da5dc 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 0000000..f8fd4cb
--- /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 86e32b8..198fc32 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 fcb08e2..1b3fbfe 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 *);