mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-27 06:48:31 +00:00
Emulate Linux socket timeout signaling on Windows
This commit is contained in:
parent
65e425fbca
commit
b14dddcc18
8 changed files with 246 additions and 29 deletions
|
@ -48,40 +48,34 @@ textwindows int sys_getsockopt_nt(struct Fd *fd, int level, int optname,
|
|||
}
|
||||
|
||||
if (level == SOL_SOCKET && optname == SO_ERROR) {
|
||||
if (in_optlen >= sizeof(int)) {
|
||||
int err;
|
||||
uint32_t len = sizeof(err);
|
||||
if (__imp_getsockopt(fd->handle, SOL_SOCKET, SO_ERROR, &err, &len) == -1)
|
||||
return __winsockerr();
|
||||
*(int *)out_opt_optval = __dos2errno(err);
|
||||
*inout_optlen = sizeof(int);
|
||||
} else {
|
||||
if (in_optlen < sizeof(int))
|
||||
return einval();
|
||||
}
|
||||
int err;
|
||||
uint32_t len = sizeof(err);
|
||||
if (__imp_getsockopt(fd->handle, SOL_SOCKET, SO_ERROR, &err, &len) == -1)
|
||||
return __winsockerr();
|
||||
*(int *)out_opt_optval = __dos2errno(err);
|
||||
*inout_optlen = sizeof(int);
|
||||
}
|
||||
|
||||
if (level == SOL_SOCKET &&
|
||||
(optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
|
||||
if (in_optlen >= sizeof(struct timeval)) {
|
||||
if (optname == SO_RCVTIMEO) {
|
||||
ms = fd->rcvtimeo;
|
||||
} else {
|
||||
ms = fd->sndtimeo;
|
||||
}
|
||||
((struct timeval *)out_opt_optval)->tv_sec = ms / 1000;
|
||||
((struct timeval *)out_opt_optval)->tv_usec = ms % 1000 * 1000;
|
||||
*inout_optlen = sizeof(struct timeval);
|
||||
return 0;
|
||||
} else {
|
||||
if (in_optlen < sizeof(struct timeval))
|
||||
return einval();
|
||||
if (optname == SO_RCVTIMEO) {
|
||||
ms = fd->rcvtimeo;
|
||||
} else {
|
||||
ms = fd->sndtimeo;
|
||||
}
|
||||
*(struct timeval *)out_opt_optval = timeval_frommillis(ms);
|
||||
*inout_optlen = sizeof(struct timeval);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO(jart): Use WSAIoctl?
|
||||
if (__imp_getsockopt(fd->handle, level, optname, out_opt_optval,
|
||||
inout_optlen) == -1) {
|
||||
inout_optlen) == -1)
|
||||
return __winsockerr();
|
||||
}
|
||||
|
||||
if (level == SOL_SOCKET) {
|
||||
if (optname == SO_LINGER && in_optlen == sizeof(struct linger)) {
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
* EPIPE (if MSG_NOSIGNAL), EMSGSIZE, ENOTSOCK, EFAULT, etc.
|
||||
* @cancelationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable (unless SO_RCVTIMEO)
|
||||
* @restartable (unless SO_RCVTIMEO on Linux or Windows)
|
||||
*/
|
||||
ssize_t recv(int fd, void *buf, size_t size, int flags) {
|
||||
ssize_t rc;
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
* EPIPE (if MSG_NOSIGNAL), EMSGSIZE, ENOTSOCK, EFAULT, etc.
|
||||
* @cancelationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable (unless SO_RCVTIMEO)
|
||||
* @restartable (unless SO_RCVTIMEO on Linux or Windows)
|
||||
*/
|
||||
ssize_t recvfrom(int fd, void *buf, size_t size, int flags,
|
||||
struct sockaddr *opt_out_srcaddr,
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
* EPIPE (if MSG_NOSIGNAL), EMSGSIZE, ENOTSOCK, EFAULT, etc.
|
||||
* @cancelationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable (unless SO_RCVTIMEO)
|
||||
* @restartable (unless SO_SNDTIMEO on Linux or Windows)
|
||||
*/
|
||||
ssize_t send(int fd, const void *buf, size_t size, int flags) {
|
||||
ssize_t rc;
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
* EPIPE (if MSG_NOSIGNAL), EMSGSIZE, ENOTSOCK, EFAULT, etc.
|
||||
* @cancelationpoint
|
||||
* @asyncsignalsafe
|
||||
* @restartable (unless SO_RCVTIMEO)
|
||||
* @restartable (unless SO_SNDTIMEO on Linux or Windows)
|
||||
*/
|
||||
ssize_t sendto(int fd, const void *buf, size_t size, int flags,
|
||||
const struct sockaddr *opt_addr, uint32_t addrsize) {
|
||||
|
|
|
@ -36,14 +36,17 @@ textwindows int sys_setsockopt_nt(struct Fd *fd, int level, int optname,
|
|||
const void *optval, uint32_t optlen) {
|
||||
|
||||
// socket read/write timeouts
|
||||
// timeout of zero means wait forever (default)
|
||||
if (level == SOL_SOCKET &&
|
||||
(optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
|
||||
if (!(optval && optlen == sizeof(struct timeval)))
|
||||
if (!optval)
|
||||
return einval();
|
||||
if (optlen < sizeof(struct timeval))
|
||||
return einval();
|
||||
const struct timeval *tv = optval;
|
||||
int64_t ms = timeval_tomillis(*tv);
|
||||
if (ms > -1u)
|
||||
ms = 0; // wait forever (default) yes zero actually means this
|
||||
ms = -1u;
|
||||
if (optname == SO_RCVTIMEO)
|
||||
fd->rcvtimeo = ms;
|
||||
if (optname == SO_SNDTIMEO)
|
||||
|
@ -51,7 +54,7 @@ textwindows int sys_setsockopt_nt(struct Fd *fd, int level, int optname,
|
|||
return 0; // we want to handle this on our own
|
||||
}
|
||||
|
||||
// how to make close() a blocking i/o call
|
||||
// how to make close() a blocking i/o call lool
|
||||
union {
|
||||
uint32_t millis;
|
||||
struct linger_nt linger;
|
||||
|
|
|
@ -191,6 +191,11 @@ __winsock_block(int64_t handle, uint32_t flags, int nonblock,
|
|||
// check if signal handler without SA_RESTART was called
|
||||
if (handler_was_called & SIG_HANDLED_NO_RESTART)
|
||||
return eintr();
|
||||
|
||||
// emulates linux behavior of having timeouts @norestart
|
||||
if (handler_was_called & SIG_HANDLED_SA_RESTART)
|
||||
if (srwtimeout)
|
||||
return eintr();
|
||||
}
|
||||
|
||||
// otherwise try the i/o operation again
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue