diff options
author | Anton Kling <anton@kling.gg> | 2024-07-06 20:46:22 +0200 |
---|---|---|
committer | Anton Kling <anton@kling.gg> | 2024-07-06 20:46:22 +0200 |
commit | 6d6289f0fb3b07b0d1a02f671df6b096318d4a4c (patch) | |
tree | 1d87fcf6374af7d4ab82cb46e1777a2ce1d3b11d /kernel | |
parent | 8e66b83b705e257b78ec98abdb86e7f8b3b5c775 (diff) |
Kernel: Add queue syscall and improve TCP
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/Makefile | 2 | ||||
-rw-r--r-- | kernel/cpu/syscall.c | 81 | ||||
-rw-r--r-- | kernel/network/tcp.c | 12 | ||||
-rw-r--r-- | kernel/queue.c | 159 | ||||
-rw-r--r-- | kernel/queue.h | 29 | ||||
-rw-r--r-- | kernel/sched/scheduler.c | 1 | ||||
-rw-r--r-- | kernel/socket.c | 31 | ||||
-rw-r--r-- | kernel/socket.h | 5 |
8 files changed, 284 insertions, 36 deletions
diff --git a/kernel/Makefile b/kernel/Makefile index a82983b..e9ef843 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -1,6 +1,6 @@ CC="i686-sb-gcc" AS="i686-sb-as" -OBJ = arch/i386/boot.o init/kernel.o cpu/gdt.o cpu/reload_gdt.o cpu/idt.o cpu/io.o libc/stdio/print.o drivers/keyboard.o log.o drivers/pit.o libc/string/memcpy.o libc/string/strlen.o libc/string/memcmp.o drivers/ata.o libc/string/memset.o cpu/syscall.o read_eip.o libc/exit/assert.o process.o libc/string/strcpy.o arch/i386/mmu.o kmalloc.o fs/ext2.o fs/vfs.o fs/devfs.o cpu/spinlock.o random.o libc/string/strcmp.o crypto/ChaCha20/chacha20.o crypto/SHA1/sha1.o fs/tmpfs.o libc/string/isequal.o drivers/pst.o kubsan.o drivers/serial.o socket.o poll.o fs/fifo.o hashmap/hashmap.o fs/shm.o elf.o ksbrk.o sched/scheduler.o libc/string/copy.o drivers/mouse.o libc/string/strlcpy.o libc/string/strcat.o drivers/vbe.o drivers/pci.o drivers/rtl8139.o network/ethernet.o network/arp.o network/bytes.o network/ipv4.o network/udp.o math.o signal.o network/tcp.o drivers/ahci.o crypto/xoshiro256plusplus/xoshiro256plusplus.o arch/i386/interrupts.o cpu/isr.o lib/stack.o lib/buffered_write.o lib/list.o cpu/arch_inst.o cpu/int_syscall.o lib/ringbuffer.o lib/relist.o arch/i386/tsc.o arch/i386/asm_tsc.o drivers/cmos.o timer.o +OBJ = arch/i386/boot.o init/kernel.o cpu/gdt.o cpu/reload_gdt.o cpu/idt.o cpu/io.o libc/stdio/print.o drivers/keyboard.o log.o drivers/pit.o libc/string/memcpy.o libc/string/strlen.o libc/string/memcmp.o drivers/ata.o libc/string/memset.o cpu/syscall.o read_eip.o libc/exit/assert.o process.o libc/string/strcpy.o arch/i386/mmu.o kmalloc.o fs/ext2.o fs/vfs.o fs/devfs.o cpu/spinlock.o random.o libc/string/strcmp.o crypto/ChaCha20/chacha20.o crypto/SHA1/sha1.o fs/tmpfs.o libc/string/isequal.o drivers/pst.o kubsan.o drivers/serial.o socket.o poll.o fs/fifo.o hashmap/hashmap.o fs/shm.o elf.o ksbrk.o sched/scheduler.o libc/string/copy.o drivers/mouse.o libc/string/strlcpy.o libc/string/strcat.o drivers/vbe.o drivers/pci.o drivers/rtl8139.o network/ethernet.o network/arp.o network/bytes.o network/ipv4.o network/udp.o math.o signal.o network/tcp.o drivers/ahci.o crypto/xoshiro256plusplus/xoshiro256plusplus.o arch/i386/interrupts.o cpu/isr.o lib/stack.o lib/buffered_write.o lib/list.o cpu/arch_inst.o cpu/int_syscall.o lib/ringbuffer.o lib/relist.o arch/i386/tsc.o arch/i386/asm_tsc.o drivers/cmos.o timer.o queue.o CFLAGS = -std=c99 -O0 -fsanitize=vla-bound,shift-exponent,pointer-overflow,shift,signed-integer-overflow,bounds -ggdb -ffreestanding -Wall -Wextra -Wno-int-conversion -Wno-unused-parameter -Werror -mgeneral-regs-only -Wimplicit-fallthrough -I./libc/include/ -I. -Wno-pointer-sign -DKERNEL LDFLAGS= INCLUDE=-I./includes/ -I../include/ -I./libc/include/ diff --git a/kernel/cpu/syscall.c b/kernel/cpu/syscall.c index 9c3dde0..0dd2356 100644 --- a/kernel/cpu/syscall.c +++ b/kernel/cpu/syscall.c @@ -16,6 +16,7 @@ #include <network/tcp.h> #include <network/udp.h> #include <poll.h> +#include <queue.h> #include <random.h> #include <socket.h> #include <string.h> @@ -553,29 +554,67 @@ int syscall_fcntl(int fd, int cmd, int arg) { return 0; } +int syscall_queue_create(void) { + return queue_create(); +} + +int syscall_queue_mod_entries(int fd, int flag, struct queue_entry *entries, + int num_entries) { + return queue_mod_entries(fd, flag, entries, num_entries); +} + +int syscall_queue_wait(int fd, struct queue_entry *events, int num_events) { + return queue_wait(fd, events, num_events); +} + int (*syscall_functions[])() = { - (void(*))syscall_open, (void(*))syscall_read, - (void(*))syscall_write, (void(*))syscall_pread, - (void(*))syscall_pwrite, (void(*))syscall_fork, - (void(*))syscall_exec, (void(*))syscall_getpid, - (void(*))syscall_exit, (void(*))syscall_wait, - (void(*))syscall_brk, (void(*))syscall_sbrk, - (void(*))syscall_pipe, (void(*))syscall_dup2, - (void(*))syscall_close, (void(*))syscall_openpty, - (void(*))syscall_poll, (void(*))syscall_mmap, - (void(*))syscall_accept, (void(*))syscall_bind, - (void(*))syscall_socket, (void(*))syscall_shm_open, - (void(*))syscall_ftruncate, (void(*))syscall_fstat, - (void(*))syscall_msleep, (void(*))syscall_uptime, - (void(*))syscall_mkdir, (void(*))syscall_recvfrom, - (void(*))syscall_sendto, (void(*))syscall_kill, - (void(*))syscall_sigaction, (void(*))syscall_chdir, - (void(*))syscall_getcwd, (void(*))syscall_isatty, - (void(*))syscall_randomfill, (void(*))syscall_munmap, - (void(*))syscall_open_process, (void(*))syscall_lseek, - (void(*))syscall_connect, (void(*))syscall_setsockopt, - (void(*))syscall_getpeername, (void(*))syscall_fcntl, + (void(*))syscall_open, + (void(*))syscall_read, + (void(*))syscall_write, + (void(*))syscall_pread, + (void(*))syscall_pwrite, + (void(*))syscall_fork, + (void(*))syscall_exec, + (void(*))syscall_getpid, + (void(*))syscall_exit, + (void(*))syscall_wait, + (void(*))syscall_brk, + (void(*))syscall_sbrk, + (void(*))syscall_pipe, + (void(*))syscall_dup2, + (void(*))syscall_close, + (void(*))syscall_openpty, + (void(*))syscall_poll, + (void(*))syscall_mmap, + (void(*))syscall_accept, + (void(*))syscall_bind, + (void(*))syscall_socket, + (void(*))syscall_shm_open, + (void(*))syscall_ftruncate, + (void(*))syscall_fstat, + (void(*))syscall_msleep, + (void(*))syscall_uptime, + (void(*))syscall_mkdir, + (void(*))syscall_recvfrom, + (void(*))syscall_sendto, + (void(*))syscall_kill, + (void(*))syscall_sigaction, + (void(*))syscall_chdir, + (void(*))syscall_getcwd, + (void(*))syscall_isatty, + (void(*))syscall_randomfill, + (void(*))syscall_munmap, + (void(*))syscall_open_process, + (void(*))syscall_lseek, + (void(*))syscall_connect, + (void(*))syscall_setsockopt, + (void(*))syscall_getpeername, + (void(*))syscall_fcntl, (void(*))syscall_clock_gettime, + (void(*))syscall_queue_create, + (void(*))syscall_queue_mod_entries, + (void(*))syscall_queue_wait, + }; void int_syscall(reg_t *r); diff --git a/kernel/network/tcp.c b/kernel/network/tcp.c index a2df3cd..8a56dd1 100644 --- a/kernel/network/tcp.c +++ b/kernel/network/tcp.c @@ -136,7 +136,10 @@ void tcp_close_connection(struct TcpConnection *con) { return; } if (TCP_STATE_ESTABLISHED == con->state) { - tcp_send_empty_payload(con, FIN); + // FIXME: + // Book says it should be FIN but observed network traffic says it + // should be FIN|ACK? + tcp_send_empty_payload(con, FIN | ACK); con->state = TCP_STATE_FIN_WAIT1; return; } @@ -192,6 +195,10 @@ int send_tcp_packet(struct TcpConnection *con, const u8 *payload, memcpy(send_buffer, &header, sizeof(header)); memcpy(send_buffer + sizeof(header), payload, payload_length); + if (header.flags & ACK) { + con->should_send_ack = 0; + } + tcp_send(con, send_buffer, send_len, con->snd_nxt, payload_length); con->snd_nxt += payload_length; @@ -290,6 +297,7 @@ void handle_tcp(ipv4_t src_ip, ipv4_t dst_ip, const u8 *payload, if (FIN & flags) { tcp_send_empty_payload(con, ACK); con->state = TCP_STATE_CLOSE_WAIT; + tcp_strip_connection(con); break; } if (tcp_payload_length > 0) { @@ -330,6 +338,8 @@ void handle_tcp(ipv4_t src_ip, ipv4_t dst_ip, const u8 *payload, case TCP_STATE_FIN_WAIT2: { if (FIN & flags) { tcp_send_empty_payload(con, ACK); + con->state = TCP_STATE_CLOSED; + tcp_destroy_connection(con); } break; } diff --git a/kernel/queue.c b/kernel/queue.c new file mode 100644 index 0000000..6d4209d --- /dev/null +++ b/kernel/queue.c @@ -0,0 +1,159 @@ +#include <assert.h> +#include <fs/vfs.h> +#include <queue.h> + +#define OBJECT_QUEUE 0x1337 + +void queue_close(vfs_fd_t *inode) { + // TODO + (void)inode; +} + +int queue_get_entries(struct queue_list *list, struct queue_entry *events, + int num_events) { + int rc = 0; + for (int i = 0; rc < num_events; i++) { + struct queue_entry *entry; + int end; + if (!relist_get(&list->entries, i, (void **)&entry, &end)) { + if (end) { + break; + } + continue; + } + if (0 == entry->listen) { + continue; + } + vfs_fd_t *ptr = get_vfs_fd(entry->fd, list->process); + if (!ptr) { + continue; + } + int should_add = 0; + if (QUEUE_WAIT_READ & entry->listen) { + if (ptr->inode->_has_data) { + if (ptr->inode->_has_data(ptr->inode)) { + should_add = 1; + } + } + } + if (QUEUE_WAIT_WRITE & entry->listen) { + if (ptr->inode->_can_write) { + if (ptr->inode->_can_write(ptr->inode)) { + should_add = 1; + } + } + } + if (should_add) { + if (events) { + memcpy(events + rc, entry, sizeof(struct queue_entry)); + } + rc++; + } + } + return rc; +} + +int queue_has_data(vfs_inode_t *inode) { + if (1 == queue_get_entries(inode->internal_object, NULL, 1)) { + return 1; + } + return 0; +} + +int queue_create(void) { + struct queue_list *list = kmalloc(sizeof(struct queue_list)); + assert(list); + relist_init(&list->entries); + list->process = current_task; + + vfs_inode_t *inode = + vfs_create_inode(0, 0, queue_has_data, NULL, 1 /*is_open*/, OBJECT_QUEUE, + list /*internal_object*/, 0, NULL, NULL, NULL, NULL, + queue_close, NULL, NULL /*get_vm_object*/, NULL, NULL, + NULL /*send_signal*/, NULL /*connect*/); + assert(inode); + return vfs_create_fd(0, 0, 0, inode, NULL); +} + +int queue_mod_entries(int fd, int flag, struct queue_entry *entries, + int num_entries) { + vfs_fd_t *fd_ptr = get_vfs_fd(fd, NULL); + assert(fd_ptr); + assert(OBJECT_QUEUE == fd_ptr->inode->internal_object_type); + struct queue_list *list = fd_ptr->inode->internal_object; + if (QUEUE_MOD_ADD == flag) { + int i = 0; + for (; i < num_entries; i++) { + struct queue_entry *copy = kmalloc(sizeof(struct queue_entry)); + if (!copy) { + break; + } + memcpy(copy, entries + i, sizeof(struct queue_entry)); + if (!relist_add(&list->entries, copy, NULL)) { + kfree(copy); + break; + } + } + return i; + } else if (QUEUE_MOD_CHANGE == flag) { + int changes = 0; + for (int i = 0; changes < num_entries; i++) { + struct queue_entry *entry; + int end; + if (!relist_get(&list->entries, i, (void **)&entry, &end)) { + if (end) { + break; + } + continue; + } + for (int j = 0; j < num_entries; j++) { + if (entry->fd == entries[j].fd) { + entry->listen = entries[j].listen; + entry->data_type = entries[j].data_type; + entry->data = entries[j].data; + changes++; + break; + } + } + } + return changes; + } else if (QUEUE_MOD_DELETE == flag) { + int changes = 0; + for (int i = 0; changes < num_entries; i++) { + struct queue_entry *entry; + int end; + if (!relist_get(&list->entries, i, (void **)&entry, &end)) { + if (end) { + break; + } + continue; + } + for (int j = 0; j < num_entries; j++) { + if (entry->fd == entries[j].fd) { + relist_remove(&list->entries, i); + kfree(entry); + break; + } + } + } + return changes; + } else { + assert(0); + } + return 0; +} + +int queue_wait(int fd, struct queue_entry *events, int num_events) { + vfs_fd_t *fd_ptr = get_vfs_fd(fd, NULL); + assert(fd_ptr); + assert(OBJECT_QUEUE == fd_ptr->inode->internal_object_type); + struct queue_list *list = fd_ptr->inode->internal_object; + int rc = queue_get_entries(list, events, num_events); + if (0 == rc) { + list_add(¤t_task->read_list, fd_ptr->inode, NULL); + switch_task(); + list_reset(¤t_task->read_list); + rc = queue_get_entries(list, events, num_events); + } + return rc; +} diff --git a/kernel/queue.h b/kernel/queue.h new file mode 100644 index 0000000..0885f16 --- /dev/null +++ b/kernel/queue.h @@ -0,0 +1,29 @@ +#include <lib/relist.h> +#include <sched/scheduler.h> +#include <typedefs.h> + +#define QUEUE_WAIT_READ (1 << 0) +#define QUEUE_WAIT_WRITE (1 << 1) + +#define QUEUE_MOD_ADD 0 +#define QUEUE_MOD_CHANGE 1 +#define QUEUE_MOD_DELETE 2 + +struct queue_entry { + int fd; + u8 listen; + int data_type; + void *data; +}; + +struct queue_list { + struct relist entries; // Store this as a binary tree(red black trees + // are used by epoll) as file + // descriptors will be used for lookups + process_t *process; +}; + +int queue_create(void); +int queue_mod_entries(int fd, int flag, struct queue_entry *entries, + int num_entries); +int queue_wait(int fd, struct queue_entry *events, int num_events); diff --git a/kernel/sched/scheduler.c b/kernel/sched/scheduler.c index a77e1e0..d04b6e7 100644 --- a/kernel/sched/scheduler.c +++ b/kernel/sched/scheduler.c @@ -441,6 +441,7 @@ process_t *next_task(process_t *s) { c = ready_queue; } if (s == c) { + ms_time = timer_get_uptime(); // wait_for_interrupt(); } if (c->sleep_until > ms_time) { diff --git a/kernel/socket.c b/kernel/socket.c index 6398d33..fbccac5 100644 --- a/kernel/socket.c +++ b/kernel/socket.c @@ -37,8 +37,6 @@ void gen_ipv4(ipv4_t *ip, u8 i1, u8 i2, u8 i3, u8 i4) { } void tcp_remove_connection(struct TcpConnection *con) { - // TODO: It should also be freed but I am unsure if a inode might - // still have a pointer(that should not be the case) for (int i = 0;; i++) { struct TcpConnection *c; int end; @@ -50,6 +48,7 @@ void tcp_remove_connection(struct TcpConnection *con) { } if (c == con) { relist_remove(&open_tcp_connections, i); + kfree(con); break; } } @@ -72,8 +71,6 @@ struct TcpConnection *tcp_connect_to_listen(ipv4_t src_ip, u16 src_port, if (TCP_STATE_LISTEN != c->state) { continue; } - kprintf("c->incoming_port: %d\n", c->incoming_port); - kprintf("dst_port: %d\n", dst_port); if (c->incoming_port == dst_port) { struct TcpConnection *new_connection = kmalloc(sizeof(struct TcpConnection)); @@ -99,8 +96,9 @@ struct TcpConnection *tcp_connect_to_listen(ipv4_t src_ip, u16 src_port, new_connection->snd_wnd = ringbuffer_unused(&new_connection->outgoing_buffer); - assert(relist_add(&open_tcp_connections, new_connection, NULL)); - assert(list_add(&c->incoming_connections, new_connection, NULL)); + u32 index; + assert(relist_add(&open_tcp_connections, new_connection, &index)); + assert(relist_add(&c->incoming_connections, new_connection, NULL)); return new_connection; } } @@ -228,11 +226,18 @@ int tcp_sync_buffer(struct TcpConnection *con) { } } +void tcp_strip_connection(struct TcpConnection *con) { + ringbuffer_free(&con->incoming_buffer); + ringbuffer_free(&con->outgoing_buffer); +} + void tcp_close(vfs_fd_t *fd) { struct TcpConnection *con = fd->inode->internal_object; assert(con); tcp_sync_buffer(con); - + if (TCP_STATE_ESTABLISHED == con->state) { + tcp_strip_connection(con); + } tcp_close_connection(con); } @@ -603,15 +608,19 @@ struct TcpConnection *tcp_get_incoming_connection(struct TcpConnection *con, int remove) { for (int i = 0;; i++) { struct TcpConnection *c; - if (!list_get(&con->incoming_connections, i, (void **)&c)) { - break; + int end; + if (!relist_get(&con->incoming_connections, i, (void **)&c, &end)) { + if (end) { + break; + } + continue; } if (!c) { continue; } if (TCP_STATE_ESTABLISHED == c->state) { if (remove) { - assert(list_set(&con->incoming_connections, i, NULL)); + assert(relist_remove(&con->incoming_connections, i)); } return c; } @@ -676,7 +685,7 @@ int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { // TODO: Move this to listen() con->state = TCP_STATE_LISTEN; - list_init(&con->incoming_connections); + relist_init(&con->incoming_connections); fd->inode->_has_data = tcp_has_incoming_connection; assert(relist_add(&open_tcp_connections, con, NULL)); return 0; diff --git a/kernel/socket.h b/kernel/socket.h index bba63c5..35074a1 100644 --- a/kernel/socket.h +++ b/kernel/socket.h @@ -5,8 +5,8 @@ typedef int socklen_t; #include <fs/fifo.h> #include <fs/vfs.h> #include <lib/buffered_write.h> -#include <lib/relist.h> #include <lib/list.h> +#include <lib/relist.h> #include <lib/ringbuffer.h> #include <lib/stack.h> #include <stddef.h> @@ -71,7 +71,7 @@ struct TcpConnection { u32 snd_max; u32 snd_wnd; - struct list incoming_connections; + struct relist incoming_connections; }; struct TcpConnection *tcp_find_connection(ipv4_t src_ip, u16 src_port, @@ -150,4 +150,5 @@ int setsockopt(int socket, int level, int option_name, const void *option_value, void tcp_remove_connection(struct TcpConnection *con); void tcp_flush_acks(void); void tcp_flush_buffers(void); +void tcp_strip_connection(struct TcpConnection *con); #endif |