summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Kling <anton@kling.gg>2024-07-06 20:46:22 +0200
committerAnton Kling <anton@kling.gg>2024-07-06 20:46:22 +0200
commit6d6289f0fb3b07b0d1a02f671df6b096318d4a4c (patch)
tree1d87fcf6374af7d4ab82cb46e1777a2ce1d3b11d
parent8e66b83b705e257b78ec98abdb86e7f8b3b5c775 (diff)
Kernel: Add queue syscall and improve TCP
-rw-r--r--kernel/Makefile2
-rw-r--r--kernel/cpu/syscall.c81
-rw-r--r--kernel/network/tcp.c12
-rw-r--r--kernel/queue.c159
-rw-r--r--kernel/queue.h29
-rw-r--r--kernel/sched/scheduler.c1
-rw-r--r--kernel/socket.c31
-rw-r--r--kernel/socket.h5
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(&current_task->read_list, fd_ptr->inode, NULL);
+ switch_task();
+ list_reset(&current_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