localsocket: implement SO_RCVTIMEO and SO_SNDTIMEO

This commit is contained in:
Matheus
2026-07-07 02:17:26 -03:00
parent c25807d976
commit c75617a6e2
3 changed files with 66 additions and 5 deletions
+2
View File
@@ -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
+16
View File
@@ -3,6 +3,7 @@
#include <util.h>
#include <stdbool.h>
#include <errno.h>
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
+48 -5
View File
@@ -5,6 +5,7 @@
#include <ringbuffer.h>
#include <kernel/vfs.h>
#include <kernel/file.h>
#include <time.h>
#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));
}
}
}