diff --git a/kernel-src/include/kernel/abi.h b/kernel-src/include/kernel/abi.h index a70eda4e..3a1c1a96 100644 --- a/kernel-src/include/kernel/abi.h +++ b/kernel-src/include/kernel/abi.h @@ -120,6 +120,8 @@ typedef struct { #define SO_PEERCRED 17 #define SO_RCVLOWAT 18 #define SO_SNDLOWAT 19 +#define SO_RCVTIMEO 20 +#define SO_SNDTIMEO 21 #define SO_BINDTODEVICE 25 #define SO_ACCEPTCONN 30 #define SO_PROTOCOL 38 diff --git a/kernel-src/include/time.h b/kernel-src/include/time.h index cee3257a..13f363d5 100644 --- a/kernel-src/include/time.h +++ b/kernel-src/include/time.h @@ -3,6 +3,7 @@ #include #include +#include typedef long time_t; typedef long suseconds_t; @@ -65,4 +66,19 @@ static inline timeval_t timespec_to_timeval(timespec_t ts) { return tv; } +static inline int timeval_to_us(timeval_t *tv, time_t *timeout_us) { + if (tv->s < 0 || tv->us < 0 || tv->us >= 1000000) + return EINVAL; + + *timeout_us = tv->s * 1000000 + tv->us; + return 0; +} + +static inline timeval_t timeval_from_us(time_t timeout_us) { + return (timeval_t) { + .s = timeout_us / 1000000, + .us = timeout_us % 1000000 + }; +} + #endif diff --git a/kernel-src/io/net/localsocket.c b/kernel-src/io/net/localsocket.c index 2a0fb53c..3dcefce8 100644 --- a/kernel-src/io/net/localsocket.c +++ b/kernel-src/io/net/localsocket.c @@ -5,6 +5,7 @@ #include #include #include +#include #define SOCKET_BUFFER (256 * 1024) #define FILE_COUNT 256 @@ -35,6 +36,8 @@ typedef struct { uintmax_t barrierwrite; // shared with pair int filesremaining[BARRIER_SIZE]; // shared with pair int bytesremaining[BARRIER_SIZE]; // shared with pair + time_t rcv_timeout_us; + time_t snd_timeout_us; bool seqpacket; localsock_cred_t cred; } localsocket_t; @@ -464,7 +467,9 @@ static int localsock_send(socket_t *socket, sockdesc_t *sockdesc) { MUTEX_RELEASE(&pair->mutex); MUTEX_RELEASE(&socket->mutex); - error = poll_dowait(&desc, 0); + error = poll_dowait(&desc, localsocket->snd_timeout_us); + if (error == ETIMEDOUT) + error = EAGAIN; poll_leave(&desc); poll_destroydesc(&desc); @@ -562,7 +567,9 @@ static int localsock_recv(socket_t *socket, sockdesc_t *sockdesc) { MUTEX_RELEASE(&pair->mutex); MUTEX_RELEASE(&socket->mutex); - error = poll_dowait(&desc, 0); + error = poll_dowait(&desc, localsocket->rcv_timeout_us); + if (error == ETIMEDOUT) + error = EAGAIN; poll_leave(&desc); poll_destroydesc(&desc); @@ -687,7 +694,9 @@ static int localsock_accept(socket_t *_server, socket_t *_clientconnection, sock MUTEX_RELEASE(&binding->mutex); MUTEX_RELEASE(&server->socket.mutex); - error = poll_dowait(&desc, 0); + error = poll_dowait(&desc, server->rcv_timeout_us); + if (error == ETIMEDOUT) + error = EAGAIN; poll_leave(&desc); poll_destroydesc(&desc); @@ -827,7 +836,9 @@ static int localsock_connect(socket_t *socket, sockaddr_t *addr, uintmax_t flags VOP_HOLD(vn); MUTEX_RELEASE(&binding->mutex); - error = poll_dowait(&desc, 0); + error = poll_dowait(&desc, localsocket->snd_timeout_us); + if (error == ETIMEDOUT) + error = EAGAIN; poll_leave(&desc); poll_destroydesc(&desc); @@ -905,7 +916,9 @@ static int localsock_connect(socket_t *socket, sockaddr_t *addr, uintmax_t flags // release and wait. once we return, we will be connected. MUTEX_RELEASE(&pair->mutex); - error = poll_dowait(&desc, 0); + error = poll_dowait(&desc, localsocket->snd_timeout_us); + if (error == ETIMEDOUT) + error = EAGAIN; poll_leave(&desc); poll_destroydesc(&desc); @@ -1264,10 +1277,32 @@ static int localsock_shutdown(socket_t *socket, int how) { // called with socket locked static int localsock_setopt(socket_t *socket, int layer, int optname, void *buffer, socklen_t len, cred_t *cred) { + localsocket_t *localsocket = (localsocket_t *)socket; int error = 0; if (layer == SOL_SOCKET) { switch (optname) { + case SO_RCVTIMEO: + case SO_SNDTIMEO: { + if (len != sizeof(timeval_t)) + return EINVAL; + + timeval_t tv; + error = USERCOPY_POSSIBLY_FROM_USER(&tv, buffer, sizeof(tv)); + if (error) + return error; + + time_t timeout_us; + error = timeval_to_us(&tv, &timeout_us); + if (error) + return error; + + if (optname == SO_RCVTIMEO) + localsocket->rcv_timeout_us = timeout_us; + else + localsocket->snd_timeout_us = timeout_us; + break; + } case SO_SNDLOWAT: case SO_OOBINLINE: case SO_KEEPALIVE: @@ -1344,6 +1379,14 @@ static int localsock_getopt(socket_t *socket, int layer, int optname, void *unsa int value = SOCKET_BUFFER; return USERCOPY_POSSIBLY_TO_USER(unsafe_buffer, &value, 4); } + case SO_RCVTIMEO: + case SO_SNDTIMEO: { + if (len != sizeof(timeval_t)) + return EINVAL; + + timeval_t tv = timeval_from_us(optname == SO_RCVTIMEO ? localsocket->rcv_timeout_us : localsocket->snd_timeout_us); + return USERCOPY_POSSIBLY_TO_USER(unsafe_buffer, &tv, sizeof(tv)); + } } }