diff options
author | Anton Kling <anton@kling.gg> | 2024-07-04 23:03:16 +0200 |
---|---|---|
committer | Anton Kling <anton@kling.gg> | 2024-07-05 12:46:50 +0200 |
commit | 6bf371cc35c11890ab18c32aabd11bf8a816e574 (patch) | |
tree | 00df8f66ec65fc8a59aa315ef90be91cadd64cb5 | |
parent | 59893c116e9e4e5dd04c24c0ba2fd06fe1936500 (diff) |
TCP: Add back support for listening on a socket
-rw-r--r-- | kernel/cpu/syscall.c | 2 | ||||
-rw-r--r-- | kernel/fs/ext2.c | 4 | ||||
-rw-r--r-- | kernel/fs/shm.c | 9 | ||||
-rw-r--r-- | kernel/fs/tmpfs.c | 4 | ||||
-rw-r--r-- | kernel/fs/vfs.c | 6 | ||||
-rw-r--r-- | kernel/fs/vfs.h | 6 | ||||
-rw-r--r-- | kernel/network/tcp.c | 16 | ||||
-rw-r--r-- | kernel/socket.c | 164 | ||||
-rw-r--r-- | kernel/socket.h | 5 |
9 files changed, 172 insertions, 44 deletions
diff --git a/kernel/cpu/syscall.c b/kernel/cpu/syscall.c index a74adfd..7653c6a 100644 --- a/kernel/cpu/syscall.c +++ b/kernel/cpu/syscall.c @@ -261,7 +261,7 @@ int syscall_open_process(int pid) { vfs_inode_t *inode = vfs_create_inode( process->pid, 0 /*type*/, 0 /*has_data*/, 0 /*can_write*/, 1 /*is_open*/, - process /*internal_object*/, 0 /*file_size*/, NULL /*open*/, + 0, process /*internal_object*/, 0 /*file_size*/, NULL /*open*/, NULL /*create_file*/, NULL /*read*/, NULL /*write*/, NULL /*close*/, NULL /*create_directory*/, NULL /*get_vm_object*/, NULL /*truncate*/, NULL /*stat*/, process_signal, NULL /*connect*/); diff --git a/kernel/fs/ext2.c b/kernel/fs/ext2.c index a61d5f2..c8c8074 100644 --- a/kernel/fs/ext2.c +++ b/kernel/fs/ext2.c @@ -742,7 +742,7 @@ vfs_inode_t *ext2_open(const char *path) { } return vfs_create_inode( - inode_num, type, NULL, NULL, 1 /*is_open*/, NULL /*internal_object*/, + inode_num, type, NULL, NULL, 1 /*is_open*/, 0, NULL /*internal_object*/, file_size, ext2_open, ext2_create_file, ext2_read, ext2_write, ext2_close, ext2_create_directory, NULL /*get_vm_object*/, ext2_truncate /*truncate*/, ext2_stat, NULL /*send_signal*/, NULL /*connect*/); @@ -957,7 +957,7 @@ vfs_inode_t *ext2_mount(void) { } vfs_inode_t *inode = vfs_create_inode( 0 /*inode_num*/, 0 /*type*/, 0 /*has_data*/, 0 /*can_write*/, - 0 /*is_open*/, NULL /*internal_object*/, 0 /*file_size*/, ext2_open, + 0 /*is_open*/, 0, NULL /*internal_object*/, 0 /*file_size*/, ext2_open, ext2_create_file, ext2_read, ext2_write, ext2_close, ext2_create_directory, NULL /*get_vm_object*/, ext2_truncate /*truncate*/, ext2_stat, NULL /*send_signal*/, NULL /*connect*/); diff --git a/kernel/fs/shm.c b/kernel/fs/shm.c index 8fcb64c..45f16f4 100644 --- a/kernel/fs/shm.c +++ b/kernel/fs/shm.c @@ -87,10 +87,11 @@ int shm_open(const char *name, int oflag, mode_t mode) { } vfs_inode_t *inode = vfs_create_inode( - 0 /*inode_num*/, 0 /*type*/, NULL, NULL, 1 /*is_open*/, internal_object, - 0 /*file_size*/, NULL /*open*/, NULL /*create_file*/, shm_read, shm_write, - NULL /*close*/, NULL /*create_directory*/, shm_get_vm_object, - shm_ftruncate, NULL /*stat*/, NULL /*send_signal*/, NULL /*connect*/); + 0 /*inode_num*/, 0 /*type*/, NULL, NULL, 1 /*is_open*/, 0, + internal_object, 0 /*file_size*/, NULL /*open*/, NULL /*create_file*/, + shm_read, shm_write, NULL /*close*/, NULL /*create_directory*/, + shm_get_vm_object, shm_ftruncate, NULL /*stat*/, NULL /*send_signal*/, + NULL /*connect*/); vfs_fd_t *fd_ptr; int fd = vfs_create_fd(oflag, mode, 0 /*is_tty*/, inode, &fd_ptr); diff --git a/kernel/fs/tmpfs.c b/kernel/fs/tmpfs.c index d418e2c..2ce8ece 100644 --- a/kernel/fs/tmpfs.c +++ b/kernel/fs/tmpfs.c @@ -55,7 +55,7 @@ void dual_pipe(int fd[2]) { int is_open = 1; void *internal_object = pipe; vfs_inode_t *inode = vfs_create_inode( - 0 /*inode_num*/, 0 /*type*/, tmp_has_data, tmp_can_write, is_open, + 0 /*inode_num*/, 0 /*type*/, tmp_has_data, tmp_can_write, is_open, 0, internal_object, 0 /*file_size*/, NULL /*open*/, NULL /*create_file*/, tmp_read, tmp_write, tmp_close, NULL /*create_directory*/, NULL /*get_vm_object*/, NULL /*truncate*/, NULL /*stat*/, @@ -86,7 +86,7 @@ void pipe(int fd[2]) { int is_open = 1; void *internal_object = pipe; vfs_inode_t *inode = vfs_create_inode( - 0 /*inode_num*/, 0 /*type*/, tmp_has_data, tmp_can_write, is_open, + 0 /*inode_num*/, 0 /*type*/, tmp_has_data, tmp_can_write, is_open, 0, internal_object, 0 /*file_size*/, NULL /*open*/, NULL /*create_file*/, tmp_read, tmp_write, tmp_close, NULL /*create_directory*/, NULL /*get_vm_object*/, NULL /*truncate*/, NULL /*stat*/, diff --git a/kernel/fs/vfs.c b/kernel/fs/vfs.c index 03352c4..65be4aa 100644 --- a/kernel/fs/vfs.c +++ b/kernel/fs/vfs.c @@ -27,8 +27,9 @@ vfs_fd_t *get_vfs_fd(int fd, process_t *p) { vfs_inode_t *vfs_create_inode( int inode_num, int type, int (*has_data)(vfs_inode_t *inode), - int (*can_write)(vfs_inode_t *inode), u8 is_open, void *internal_object, - u64 file_size, vfs_inode_t *(*open)(const char *path), + int (*can_write)(vfs_inode_t *inode), u8 is_open, int internal_object_type, + void *internal_object, u64 file_size, + vfs_inode_t *(*open)(const char *path), int (*create_file)(const char *path, int mode), int (*read)(u8 *buffer, u64 offset, u64 len, vfs_fd_t *fd), int (*write)(u8 *buffer, u64 offset, u64 len, vfs_fd_t *fd), @@ -46,6 +47,7 @@ vfs_inode_t *vfs_create_inode( r->_has_data = has_data; r->_can_write = can_write; r->is_open = is_open; + r->internal_object_type = internal_object_type; r->internal_object = internal_object; r->file_size = file_size; r->open = open; diff --git a/kernel/fs/vfs.h b/kernel/fs/vfs.h index 3bb7f74..a39982d 100644 --- a/kernel/fs/vfs.h +++ b/kernel/fs/vfs.h @@ -49,6 +49,7 @@ struct vfs_inode { int (*_has_data)(vfs_inode_t *iinode); int (*_can_write)(vfs_inode_t *iinode); u8 is_open; + int internal_object_type; void *internal_object; u64 file_size; vfs_inode_t *(*open)(const char *path); @@ -84,8 +85,9 @@ int vfs_chdir(const char *path); int vfs_fstat(int fd, struct stat *buf); vfs_inode_t *vfs_create_inode( int inode_num, int type, int (*has_data)(vfs_inode_t *inode), - int (*can_write)(vfs_inode_t *inode), u8 is_open, void *internal_object, - u64 file_size, vfs_inode_t *(*open)(const char *path), + int (*can_write)(vfs_inode_t *inode), u8 is_open, int internal_object_type, + void *internal_object, u64 file_size, + vfs_inode_t *(*open)(const char *path), int (*create_file)(const char *path, int mode), int (*read)(u8 *buffer, u64 offset, u64 len, vfs_fd_t *fd), int (*write)(u8 *buffer, u64 offset, u64 len, vfs_fd_t *fd), diff --git a/kernel/network/tcp.c b/kernel/network/tcp.c index 6bec93e..a2df3cd 100644 --- a/kernel/network/tcp.c +++ b/kernel/network/tcp.c @@ -224,9 +224,15 @@ void handle_tcp(ipv4_t src_ip, ipv4_t dst_ip, const u8 *payload, u32 seq_num = htonl(n_seq_num); u32 ack_num = htonl(n_ack_num); u16 window_size = htons(n_window_size); - struct TcpConnection *con = - tcp_find_connection(src_ip, src_port, dst_ip, dst_port); + + struct TcpConnection *con = NULL; + if (SYN == flags) { + con = tcp_connect_to_listen(src_ip, src_port, dst_ip, dst_port); + } else { + con = tcp_find_connection(src_ip, src_port, dst_ip, dst_port); + } if (!con) { + kprintf("Unable to find connection for port: %d\n", dst_port); return; } @@ -321,6 +327,12 @@ void handle_tcp(ipv4_t src_ip, ipv4_t dst_ip, const u8 *payload, } break; } + case TCP_STATE_FIN_WAIT2: { + if (FIN & flags) { + tcp_send_empty_payload(con, ACK); + } + break; + } case TCP_STATE_CLOSE_WAIT: { // Waiting for this machine to close the connection. There is // nothing to respond with. diff --git a/kernel/socket.c b/kernel/socket.c index 82e8140..6398d33 100644 --- a/kernel/socket.c +++ b/kernel/socket.c @@ -5,6 +5,7 @@ #include <fs/tmpfs.h> #include <interrupts.h> #include <lib/ringbuffer.h> +#include <lib/stack.h> #include <math.h> #include <network/bytes.h> #include <network/tcp.h> @@ -15,9 +16,15 @@ #include <stdatomic.h> #include <sys/socket.h> +#define OBJECT_UNIX 0 +#define OBJECT_TCP 1 + struct list open_udp_connections; struct relist open_tcp_connections; +struct TcpConnection *tcp_get_incoming_connection(struct TcpConnection *con, + int remove); + void global_socket_init(void) { list_init(&open_udp_connections); relist_init(&open_tcp_connections); @@ -48,6 +55,58 @@ void tcp_remove_connection(struct TcpConnection *con) { } } +struct TcpConnection *tcp_connect_to_listen(ipv4_t src_ip, u16 src_port, + ipv4_t dst_ip, u16 dst_port) { + for (int i = 0;; i++) { + struct TcpConnection *c; + int end; + if (!relist_get(&open_tcp_connections, i, (void **)&c, &end)) { + if (end) { + break; + } + continue; + } + if (TCP_STATE_CLOSED == c->state) { + continue; + } + 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)); + memcpy(new_connection, c, sizeof(struct TcpConnection)); + new_connection->outgoing_port = src_port; + new_connection->outgoing_ip = src_ip.d; + new_connection->state = TCP_STATE_LISTEN; + new_connection->rcv_wnd = 65535; + + ringbuffer_init(&new_connection->outgoing_buffer, 8192); + ringbuffer_init(&new_connection->incoming_buffer, + new_connection->rcv_wnd * 64); + new_connection->max_seg = 1; + + new_connection->rcv_nxt = 0; + new_connection->rcv_adv = 0; + + new_connection->snd_una = 0; + new_connection->snd_nxt = 0; + new_connection->snd_max = 0; + new_connection->snd_wnd = 0; + new_connection->sent_ack = 0; + + 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)); + return new_connection; + } + } + return NULL; +} + struct TcpConnection *tcp_find_connection(ipv4_t src_ip, u16 src_port, ipv4_t dst_ip, u16 dst_port) { for (int i = 0;; i++) { @@ -197,6 +256,9 @@ int tcp_has_data(vfs_inode_t *inode) { int tcp_can_write(vfs_inode_t *inode) { struct TcpConnection *con = inode->internal_object; + if (TCP_STATE_ESTABLISHED != con->state) { + return 0; + } if (con->no_delay) { return (0 != tcp_can_send(con)); } @@ -480,8 +542,8 @@ int accept(int socket, struct sockaddr *address, socklen_t *address_len) { vfs_fd_t *fd_ptr = get_vfs_fd(socket, NULL); assert(fd_ptr); vfs_inode_t *inode = fd_ptr->inode; - SOCKET *s = (SOCKET *)inode->internal_object; - if (AF_UNIX == s->domain) { + if (OBJECT_UNIX == inode->internal_object_type) { + SOCKET *s = (SOCKET *)inode->internal_object; for (; NULL == s->incoming_fd;) { // Wait until we have gotten a connection struct pollfd fds[1]; @@ -497,10 +559,11 @@ int accept(int socket, struct sockaddr *address, socklen_t *address_len) { s->incoming_fd = NULL; return index; } - if (AF_INET == s->domain) { - struct TcpListen *tcp_listen = s->object; - assert(tcp_listen); - if (stack_isempty(&tcp_listen->incoming_connections)) { + if (OBJECT_TCP == inode->internal_object_type) { + struct TcpConnection *con = inode->internal_object; + + struct TcpConnection *connection = tcp_get_incoming_connection(con, 1); + if (!connection) { if (fd_ptr->flags & O_NONBLOCK) { return -EWOULDBLOCK; } @@ -508,17 +571,17 @@ int accept(int socket, struct sockaddr *address, socklen_t *address_len) { fds[0].fd = socket; fds[0].events = POLLIN; fds[0].revents = 0; - poll(fds, 1, 0); + for (; 1 != poll(fds, 1, 0);) + ; + connection = tcp_get_incoming_connection(con, 1); } - struct TcpConnection *connection = - 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, tcp_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*/, NULL /*connect*/); + OBJECT_TCP, 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*/, NULL /*connect*/); assert(inode); return vfs_create_fd(O_RDWR, 0, 0 /*is_tty*/, inode, NULL); } @@ -536,6 +599,35 @@ int bind_can_write(vfs_inode_t *inode) { return 1; } +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; + } + if (!c) { + continue; + } + if (TCP_STATE_ESTABLISHED == c->state) { + if (remove) { + assert(list_set(&con->incoming_connections, i, NULL)); + } + return c; + } + // TODO: More handling with dead connections? + } + return NULL; +} + +int tcp_has_incoming_connection(vfs_inode_t *inode) { + struct TcpConnection *con = inode->internal_object; + if (NULL != tcp_get_incoming_connection(con, 0)) { + return 1; + } + return 0; +} + int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { (void)addrlen; vfs_fd_t *fd = get_vfs_fd(sockfd, NULL); @@ -549,8 +641,8 @@ int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { if (FS_TYPE_UNIX_SOCKET != inode->type) { return -ENOTSOCK; } - SOCKET *s = (SOCKET *)inode->internal_object; - if (AF_UNIX == s->domain) { + if (OBJECT_UNIX == inode->internal_object_type) { + SOCKET *s = (SOCKET *)inode->internal_object; struct sockaddr_un *un = (struct sockaddr_un *)addr; size_t path_len = strlen(un->sun_path); s->path = kmalloc(path_len + 1); @@ -573,8 +665,20 @@ int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { devfs_add_file(us->path, NULL, NULL, NULL, NULL, bind_can_write, FS_TYPE_UNIX_SOCKET); return 0; - } else if (AF_INET == s->domain) { - assert(0); + } else if (OBJECT_TCP == inode->internal_object_type) { + struct TcpConnection *con = inode->internal_object; + // TODO: These should not be asserts + assert(AF_INET == addr->sa_family); + assert(addrlen == sizeof(struct sockaddr_in)); + struct sockaddr_in *in = (struct sockaddr_in *)addr; + con->incoming_port = ntohs(in->sin_port); // TODO: Check so that it can + // actually do this + + // TODO: Move this to listen() + con->state = TCP_STATE_LISTEN; + list_init(&con->incoming_connections); + fd->inode->_has_data = tcp_has_incoming_connection; + assert(relist_add(&open_tcp_connections, con, NULL)); return 0; } ASSERT_NOT_REACHED; @@ -617,10 +721,11 @@ int tcp_create_fd(int is_nonblock) { con->should_send_ack = 0; vfs_inode_t *inode = vfs_create_inode( - 0 /*inode_num*/, FS_TYPE_UNIX_SOCKET, NULL, always_can_write, 1, con, - 0 /*file_size*/, NULL /*open*/, NULL /*create_file*/, tcp_read, tcp_write, - NULL /*close*/, NULL /*create_directory*/, NULL /*get_vm_object*/, - NULL /*truncate*/, NULL /*stat*/, NULL /*send_signal*/, tcp_connect); + 0 /*inode_num*/, FS_TYPE_UNIX_SOCKET, NULL, always_can_write, 1, + OBJECT_TCP, con, 0 /*file_size*/, NULL /*open*/, NULL /*create_file*/, + tcp_read, tcp_write, NULL /*close*/, NULL /*create_directory*/, + NULL /*get_vm_object*/, NULL /*truncate*/, NULL /*stat*/, + NULL /*send_signal*/, tcp_connect); if (!inode) { kfree(con); return -ENOMEM; @@ -657,11 +762,11 @@ int socket(int domain, int type, int protocol) { if (AF_UNIX == domain) { vfs_inode_t *inode = vfs_create_inode( 0 /*inode_num*/, FS_TYPE_UNIX_SOCKET, bind_has_data, socket_can_write, - 1 /*is_open*/, new_socket /*internal_object*/, 0 /*file_size*/, - NULL /*open*/, NULL /*create_file*/, socket_read, socket_write, - socket_close, NULL /*create_directory*/, NULL /*get_vm_object*/, - NULL /*truncate*/, NULL /*stat*/, NULL /*send_signal*/, - NULL /*connect*/); + 1 /*is_open*/, OBJECT_UNIX, new_socket /*internal_object*/, + 0 /*file_size*/, NULL /*open*/, NULL /*create_file*/, socket_read, + socket_write, socket_close, NULL /*create_directory*/, + NULL /*get_vm_object*/, NULL /*truncate*/, NULL /*stat*/, + NULL /*send_signal*/, NULL /*connect*/); if (!inode) { rc = -ENOMEM; goto socket_error; @@ -688,9 +793,10 @@ int socket(int domain, int type, int protocol) { vfs_inode_t *inode = vfs_create_inode( 0 /*inode_num*/, FS_TYPE_UNIX_SOCKET, NULL, always_can_write, 1, - new_socket, 0 /*file_size*/, NULL /*open*/, NULL /*create_file*/, NULL, - NULL, NULL /*close*/, NULL /*create_directory*/, NULL /*get_vm_object*/, - NULL /*truncate*/, NULL /*stat*/, NULL /*send_signal*/, udp_connect); + OBJECT_UNIX, new_socket, 0 /*file_size*/, NULL /*open*/, + NULL /*create_file*/, NULL, NULL, NULL /*close*/, + NULL /*create_directory*/, NULL /*get_vm_object*/, NULL /*truncate*/, + NULL /*stat*/, NULL /*send_signal*/, udp_connect); if (!inode) { rc = -ENOMEM; goto socket_error; diff --git a/kernel/socket.h b/kernel/socket.h index 5ea71f5..bba63c5 100644 --- a/kernel/socket.h +++ b/kernel/socket.h @@ -6,6 +6,7 @@ typedef int socklen_t; #include <fs/vfs.h> #include <lib/buffered_write.h> #include <lib/relist.h> +#include <lib/list.h> #include <lib/ringbuffer.h> #include <lib/stack.h> #include <stddef.h> @@ -69,10 +70,14 @@ struct TcpConnection { u32 snd_nxt; u32 snd_max; u32 snd_wnd; + + struct list incoming_connections; }; struct TcpConnection *tcp_find_connection(ipv4_t src_ip, u16 src_port, ipv4_t dst_ip, u16 dst_port); +struct TcpConnection *tcp_connect_to_listen(ipv4_t src_ip, u16 src_port, + ipv4_t dst_ip, u16 dst_port); struct UdpConnection *udp_find_connection(ipv4_t src_ip, u16 src_port, u16 dst_port); |