diff options
author | Anton Kling <anton@kling.gg> | 2024-04-29 22:00:55 +0200 |
---|---|---|
committer | Anton Kling <anton@kling.gg> | 2024-04-29 22:00:55 +0200 |
commit | 231301a6190605bd3ced4d961ee0d5d3fcd49d65 (patch) | |
tree | 8af67c28f9b638393f700fbaf2c9e33fd97a8b46 /kernel | |
parent | 7d2ab3a71f4bda9d8ee997764d98b29e13a902c5 (diff) |
Kernel/IRC: Add setsockopt and move IRC client to use new socket interface
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/cpu/syscall.c | 6 | ||||
-rw-r--r-- | kernel/socket.c | 51 | ||||
-rw-r--r-- | kernel/socket.h | 4 | ||||
-rw-r--r-- | kernel/syscalls/lseek.c | 34 |
4 files changed, 86 insertions, 9 deletions
diff --git a/kernel/cpu/syscall.c b/kernel/cpu/syscall.c index 84faa16..b72beff 100644 --- a/kernel/cpu/syscall.c +++ b/kernel/cpu/syscall.c @@ -145,6 +145,11 @@ int syscall_connect(int sockfd, const struct sockaddr *addr, return connect(sockfd, addr, addrlen); } +int syscall_setsockopt(int socket, int level, int option_name, + const void *option_value, socklen_t option_len) { + return setsockopt(socket, level, option_name, option_value, option_len); +} + int (*syscall_functions[])() = { (void(*))syscall_open, (void(*))syscall_mread, @@ -198,6 +203,7 @@ int (*syscall_functions[])() = { (void(*))syscall_open_process, (void(*))syscall_lseek, (void(*))syscall_connect, + (void(*))syscall_setsockopt, }; void int_syscall(reg_t *r); diff --git a/kernel/socket.c b/kernel/socket.c index fbc0648..d952052 100644 --- a/kernel/socket.c +++ b/kernel/socket.c @@ -8,6 +8,7 @@ #include <poll.h> #include <sched/scheduler.h> #include <socket.h> +#include <sys/socket.h> struct list open_tcp_connections; struct list open_tcp_listen; @@ -70,6 +71,7 @@ struct TcpConnection *internal_tcp_incoming(u32 src_ip, u16 src_port, con->outgoing_port = src_port; con->incoming_ip = dst_ip; con->incoming_port = dst_port; + con->no_delay = 0; ringbuffer_init(&con->incoming_buffer, 8192); ringbuffer_init(&con->outgoing_buffer, 8192); @@ -126,6 +128,11 @@ int tcp_write(u8 *buffer, u64 offset, u64 len, vfs_fd_t *fd) { return -EBADF; // TODO: Check if this is correct. } + if (con->no_delay) { + send_tcp_packet(con, buffer, len); + return len; + } + struct ringbuffer *rb = &con->outgoing_buffer; if (ringbuffer_unused(rb) < len) { tcp_sync_buffer(fd); @@ -144,10 +151,8 @@ int tcp_has_data(vfs_inode_t *inode) { int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { vfs_fd_t *fd = get_vfs_fd(sockfd, NULL); - assert(fd); - - if (fd->inode->internal_object) { - return -EISCONN; + if (!fd) { + return -EBADF; } assert(AF_INET == addr->sa_family); @@ -159,7 +164,7 @@ int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { con->incoming_port = 1337; // TODO con->outgoing_ip = in_addr->sin_addr.s_addr; - con->outgoing_port = in_addr->sin_port; + con->outgoing_port = ntohs(in_addr->sin_port); ringbuffer_init(&con->incoming_buffer, 8192); ringbuffer_init(&con->outgoing_buffer, 8192); @@ -185,6 +190,35 @@ int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { return 0; } +int setsockopt(int socket, int level, int option_name, const void *option_value, + socklen_t option_len) { + vfs_fd_t *fd = get_vfs_fd(socket, NULL); + if (!fd) { + return -EBADF; + } + // TODO: Check that it is actually a TCP socket + if (IPPROTO_TCP == level) { + struct TcpConnection *tcp_connection = fd->inode->internal_object; + switch (option_name) { + case TCP_NODELAY: { + if (sizeof(int) != option_len) { + return -EINVAL; + } + if (!mmu_is_valid_userpointer(option_value, option_len)) { + return -EPERM; // TODO: Check if this is correct + } + int value = *(int *)option_value; + tcp_connection->no_delay = value; + } break; + default: + return -ENOPROTOOPT; + break; + } + return 0; + } + return -ENOPROTOOPT; +} + int uds_open(const char *path) { // FIXME: This is super ugly @@ -268,10 +302,9 @@ int accept(int socket, struct sockaddr *address, socklen_t *address_len) { stack_pop(&tcp_listen->incoming_connections); assert(connection); vfs_inode_t *inode = vfs_create_inode( - 0 /*inode_num*/, FS_TYPE_UNIX_SOCKET, tcp_has_data, - always_can_write, 1, connection, 0 /*file_size*/, NULL /*open*/, - NULL /*create_file*/, tcp_read, tcp_write, - tcp_close /*close*/, NULL /*create_directory*/, + 0 /*inode_num*/, FS_TYPE_UNIX_SOCKET, tcp_has_data, always_can_write, 1, + connection, 0 /*file_size*/, NULL /*open*/, NULL /*create_file*/, + tcp_read, tcp_write, tcp_close /*close*/, NULL /*create_directory*/, NULL /*get_vm_object*/, NULL /*truncate*/, NULL /*stat*/, NULL /*send_signal*/); assert(inode); diff --git a/kernel/socket.h b/kernel/socket.h index b542c87..3d1025d 100644 --- a/kernel/socket.h +++ b/kernel/socket.h @@ -38,6 +38,8 @@ struct TcpConnection { struct ringbuffer incoming_buffer; struct ringbuffer outgoing_buffer; + int no_delay; + u32 seq; u32 ack; @@ -116,4 +118,6 @@ struct INCOMING_TCP_CONNECTION *get_incoming_tcp_connection(u8 ip[4], int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); void global_socket_init(void); u16 tcp_get_free_port(void); +int setsockopt(int socket, int level, int option_name, const void *option_value, + socklen_t option_len); #endif diff --git a/kernel/syscalls/lseek.c b/kernel/syscalls/lseek.c new file mode 100644 index 0000000..3e38822 --- /dev/null +++ b/kernel/syscalls/lseek.c @@ -0,0 +1,34 @@ +#include <assert.h> +#include <errno.h> +#include <fs/vfs.h> + +// FIXME: These should be in a shared header file with libc +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +off_t syscall_lseek(int fd, off_t offset, int whence) { + vfs_fd_t *fd_ptr = get_vfs_fd(fd, NULL); + if (!fd_ptr) { + return -EBADF; + } + + off_t ret_offset = fd_ptr->offset; + switch (whence) { + case SEEK_SET: + ret_offset = offset; + break; + case SEEK_CUR: + ret_offset += offset; + break; + case SEEK_END: + assert(fd_ptr->inode); + ret_offset = fd_ptr->inode->file_size + offset; + break; + default: + return -EINVAL; + break; + } + fd_ptr->offset = ret_offset; + return ret_offset; +} |