diff --git a/kernel-src/fs/sockfs.c b/kernel-src/fs/sockfs.c index 63c31b57..784ae66d 100644 --- a/kernel-src/fs/sockfs.c +++ b/kernel-src/fs/sockfs.c @@ -195,7 +195,7 @@ int sockfs_ioctl(vnode_t *node, unsigned long request, void *arg, int *result, c free(dev); return e; } - case FIONREAD: { + case FIONREAD: { socket_t *socket = SOCKFS_SOCKET_FROM_NODE(node); if (socket->ops->datacount == NULL) return ENOTTY; @@ -203,9 +203,21 @@ int sockfs_ioctl(vnode_t *node, unsigned long request, void *arg, int *result, c int count = socket->ops->datacount(socket); return USERCOPY_POSSIBLY_TO_USER(arg, &count, sizeof(int)); } - default: - printf("got unknown socket ioctl %lu\n", request); - return ENOTTY; + case FIONBIO: { + int nonblocking; + int e = USERCOPY_POSSIBLY_FROM_USER(&nonblocking, arg, sizeof(nonblocking)); + if (e) + return e; + + socket_t *socket = SOCKFS_SOCKET_FROM_NODE(node); + MUTEX_ACQUIRE(&socket->mutex); + socket->nonblocking = nonblocking != 0; + MUTEX_RELEASE(&socket->mutex); + return 0; + } + default: + printf("got unknown socket ioctl %lu\n", request); + return ENOTTY; } return 0; } diff --git a/kernel-src/include/kernel/abi.h b/kernel-src/include/kernel/abi.h index e3d15419..442ebc19 100644 --- a/kernel-src/include/kernel/abi.h +++ b/kernel-src/include/kernel/abi.h @@ -165,6 +165,7 @@ typedef struct { #define SIOCGIFHWADDR 0x8927 #define SIOCADDRT 0x890b #define FIONREAD 0x541B +#define FIONBIO 0x5421 typedef struct { char name[IFNAMSIZ]; diff --git a/kernel-src/include/kernel/sock.h b/kernel-src/include/kernel/sock.h index 77ecc891..85ba127d 100644 --- a/kernel-src/include/kernel/sock.h +++ b/kernel-src/include/kernel/sock.h @@ -7,6 +7,7 @@ #include #include #include +#include #define SOCKET_STATE_UNBOUND 0 #define SOCKET_STATE_BOUND 1 @@ -27,6 +28,7 @@ typedef struct { int type; int shutdown; int error; + bool nonblocking; } socket_t; typedef struct { @@ -89,6 +91,10 @@ typedef struct { #define SOCKET_TYPE_TCP 2 #define SOCKFS_SOCKET_FROM_NODE(nodep) (((socketnode_t *)(nodep))->socket) +static inline bool socket_nonblocking(socket_t *socket, uintmax_t flags) { + return socket->nonblocking || (flags & V_FFLAGS_NONBLOCKING); +} + static inline int socket_recv(socket_t *socket, void *buffer, size_t size, uintmax_t flags, size_t *bytes_read) { iovec_iterator_t iovec_iterator; diff --git a/kernel-src/io/net/localsocket.c b/kernel-src/io/net/localsocket.c index c9e8bd21..67785f5c 100644 --- a/kernel-src/io/net/localsocket.c +++ b/kernel-src/io/net/localsocket.c @@ -342,7 +342,7 @@ static int localsock_send(socket_t *socket, sockdesc_t *sockdesc) { break; } - if (sockdesc->flags & V_FFLAGS_NONBLOCKING) { + if (socket_nonblocking(socket, sockdesc->flags)) { error = EAGAIN; poll_leave(&desc); poll_destroydesc(&desc); @@ -433,7 +433,7 @@ static int localsock_recv(socket_t *socket, sockdesc_t *sockdesc) { } } - if (flags & V_FFLAGS_NONBLOCKING) { + if (socket_nonblocking(socket, flags)) { error = EAGAIN; poll_leave(&desc); poll_destroydesc(&desc); @@ -549,7 +549,7 @@ static int localsock_accept(socket_t *_server, socket_t *_clientconnection, sock break; } - if (flags & V_FFLAGS_NONBLOCKING) { + if (socket_nonblocking(&server->socket, flags)) { error = EAGAIN; poll_leave(&desc); poll_destroydesc(&desc); @@ -664,7 +664,7 @@ static int localsock_connect(socket_t *socket, sockaddr_t *addr, uintmax_t flags break; } - if (flags & V_FFLAGS_NONBLOCKING) { + if (socket_nonblocking(socket, flags)) { error = EAGAIN; poll_leave(&desc); poll_destroydesc(&desc); @@ -722,7 +722,7 @@ static int localsock_connect(socket_t *socket, sockaddr_t *addr, uintmax_t flags // if nonblocking, return success. the userspace/whatever will // poll() the client to know when they can send data or if the server gave up and closed - if (flags & V_FFLAGS_NONBLOCKING) { + if (socket_nonblocking(socket, flags)) { error = 0; goto leave; } diff --git a/kernel-src/io/net/socket.c b/kernel-src/io/net/socket.c index 6ae72a55..cc81f0d2 100644 --- a/kernel-src/io/net/socket.c +++ b/kernel-src/io/net/socket.c @@ -17,6 +17,7 @@ socket_t *socket_create(int type) { socket->state = SOCKET_STATE_UNBOUND; MUTEX_INIT(&socket->mutex); socket->type = type; + socket->nonblocking = false; return socket; } diff --git a/kernel-src/io/net/tcp.c b/kernel-src/io/net/tcp.c index e6eefef7..8457b157 100644 --- a/kernel-src/io/net/tcp.c +++ b/kernel-src/io/net/tcp.c @@ -1294,7 +1294,7 @@ static int tcp_send(socket_t *socket, sockdesc_t *sockdesc) { break; } - if (revents & V_FFLAGS_NONBLOCKING) { + if (socket_nonblocking(socket, sockdesc->flags)) { poll_leave(&polldesc); poll_destroydesc(&polldesc); error = EAGAIN; @@ -1374,7 +1374,7 @@ static int tcp_recv(socket_t *socket, sockdesc_t *sockdesc) { } } - if (flags & V_FFLAGS_NONBLOCKING) { + if (socket_nonblocking(socket, flags)) { error = EAGAIN; poll_leave(&desc); poll_destroydesc(&desc); @@ -1587,7 +1587,7 @@ static int tcp_connect(socket_t *socket, sockaddr_t *addr, uintmax_t flags, cred tcpsocket->tcb = tcb; } - if (flags & V_FFLAGS_NONBLOCKING) { + if (socket_nonblocking(socket, flags)) { error = EINPROGRESS; goto cleanup; } @@ -1707,7 +1707,7 @@ static int tcp_accept(socket_t *server, socket_t *client, sockaddr_t *addr, uint break; } - if (flags & V_FFLAGS_NONBLOCKING) { + if (socket_nonblocking(server, flags)) { error = EAGAIN; poll_leave(&desc); poll_destroydesc(&desc); diff --git a/kernel-src/io/net/udp.c b/kernel-src/io/net/udp.c index 00744cba..d929e081 100644 --- a/kernel-src/io/net/udp.c +++ b/kernel-src/io/net/udp.c @@ -242,7 +242,7 @@ static int udp_recv(socket_t *socket, sockdesc_t *sockdesc) { break; } - if (flags & V_FFLAGS_NONBLOCKING) { + if (socket_nonblocking(socket, flags)) { e = EAGAIN; poll_leave(&desc); poll_destroydesc(&desc);