Cygwin: sockets: Handle SO_RCVTIMEO and SO_SNDTIMEO

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
Corinna Vinschen 2018-02-07 16:16:51 +01:00
parent 51af517cab
commit c51a0b74dc
6 changed files with 98 additions and 2 deletions

View File

@ -523,6 +523,13 @@ class fhandler_socket: public fhandler_base
void rmem (int nrmem) { _rmem = nrmem; }
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:

View File

@ -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:

View File

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

View File

@ -0,0 +1,13 @@
What's new:
-----------
What changed:
-------------
- SO_RCVTIMEO and SO_SNDTIMEO socket options are now honored.
Bug Fixes
---------

View File

@ -215,6 +215,22 @@ timeval_to_filetime (const struct timeval *time_in, PLARGE_INTEGER out)
+ time_in->tv_usec * (NS100PERSEC/USPERSEC) + FACTOR;
}
/* 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)

View File

@ -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 *);