diff options
author | Anton Kling <anton@kling.gg> | 2023-10-27 19:41:26 +0200 |
---|---|---|
committer | Anton Kling <anton@kling.gg> | 2023-10-30 21:49:48 +0100 |
commit | 4f9ed7087cb58683d9423ab771ad76b31dac5514 (patch) | |
tree | 5364217b7d491c4321830025020ab13513067cb1 /scalls/recvfrom.c | |
parent | 715274d3a77c58510b97c3f87cd604dde9de7a4f (diff) |
Kernel: Expose source information of incoming UDP packets
Diffstat (limited to 'scalls/recvfrom.c')
-rw-r--r-- | scalls/recvfrom.c | 52 |
1 files changed, 48 insertions, 4 deletions
diff --git a/scalls/recvfrom.c b/scalls/recvfrom.c index 0e37153..1770fa1 100644 --- a/scalls/recvfrom.c +++ b/scalls/recvfrom.c @@ -1,15 +1,59 @@ +#include <assert.h> #include <fs/vfs.h> +#include <math.h> #include <poll.h> #include <scalls/recvfrom.h> -size_t syscall_recvfrom(int socket, void *buffer, size_t length, int flags, - struct sockaddr *address, socklen_t *address_len) { +size_t syscall_recvfrom( + int socket, void *buffer, size_t length, int flags, + struct two_args + *extra_args /*struct sockaddr *address, socklen_t *address_len*/) { + + struct sockaddr *address = (struct sockaddr *)extra_args->a; + socklen_t *address_len = (socklen_t *)extra_args->b; + kprintf("address: %x\n", address); + kprintf("address_len: %x\n", address_len); + if (flags & MSG_WAITALL) { struct pollfd fds[1]; fds[0].fd = socket; fds[0].events = POLLIN; poll(fds, 1, 0); } - kprintf("got event\n"); - return vfs_pread(socket, buffer, length, 0); + + uint16_t data_length; + socklen_t tmp_socklen; + vfs_pread(socket, &tmp_socklen, sizeof(socklen_t), 0); + if (address_len) + *address_len = tmp_socklen; + if (address) { + vfs_pread(socket, address, tmp_socklen, 0); + } else { + // We still have to throwaway the data. + char devnull[100]; + for (; tmp_socklen;) { + int rc = vfs_pread(socket, devnull, min(tmp_socklen, 100), 0); + assert(rc >= 0); + tmp_socklen -= rc; + } + } + + vfs_pread(socket, &data_length, sizeof(data_length), 0); + // If it is reading less than the packet length that could cause + // problems as the next read will not be put at a new header. Luckily + // it seems as if other UNIX systems can discard the rest of the + // packet if not read. + + // Read in the data requested + int read_len = min(length, data_length); + int rc = vfs_pread(socket, buffer, read_len, 0); + // Discard the rest of the packet + int rest = data_length - read_len; + char devnull[100]; + for (; rest;) { + int rc = vfs_pread(socket, devnull, 100, 0); + assert(rc >= 0); + rest -= rc; + } + return rc; } |