diff options
author | Anton Kling <anton@kling.gg> | 2024-06-22 14:34:21 +0200 |
---|---|---|
committer | Anton Kling <anton@kling.gg> | 2024-06-22 14:34:21 +0200 |
commit | 01b88a7bf9fb4c78bd632bfccb06f3d320a21fd5 (patch) | |
tree | 20d9a6dcc155e7c8b6e067c6ba6d7b42df4365fd /kernel/socket.c | |
parent | af313dec6b7698b6f948b97669aa7be91717a451 (diff) |
Kernel stuff
Diffstat (limited to 'kernel/socket.c')
-rw-r--r-- | kernel/socket.c | 204 |
1 files changed, 93 insertions, 111 deletions
diff --git a/kernel/socket.c b/kernel/socket.c index 79121e7..5aeeb93 100644 --- a/kernel/socket.c +++ b/kernel/socket.c @@ -3,6 +3,7 @@ #include <fs/devfs.h> #include <fs/tmpfs.h> #include <interrupts.h> +#include <lib/ringbuffer.h> #include <math.h> #include <network/bytes.h> #include <network/tcp.h> @@ -10,16 +11,15 @@ #include <poll.h> #include <sched/scheduler.h> #include <socket.h> +#include <stdatomic.h> #include <sys/socket.h> struct list open_udp_connections; struct list open_tcp_connections; -struct list open_tcp_listen; void global_socket_init(void) { list_init(&open_udp_connections); list_init(&open_tcp_connections); - list_init(&open_tcp_listen); } OPEN_UNIX_SOCKET *un_sockets[100] = {0}; @@ -32,13 +32,15 @@ void gen_ipv4(ipv4_t *ip, u8 i1, u8 i2, u8 i3, u8 i4) { } struct TcpConnection *tcp_find_connection(ipv4_t src_ip, u16 src_port, - u16 dst_port) { - (void)src_ip; + ipv4_t dst_ip, u16 dst_port) { for (int i = 0;; i++) { struct TcpConnection *c; if (!list_get(&open_tcp_connections, i, (void **)&c)) { break; } + if (TCP_STATE_CLOSED == c->state) { + continue; + } if (c->incoming_port == dst_port && c->outgoing_port == src_port) { return c; } @@ -64,50 +66,10 @@ struct UdpConnection *udp_find_connection(ipv4_t src_ip, u16 src_port, return NULL; } -struct TcpListen *tcp_find_listen(u16 port) { - for (int i = 0;; i++) { - struct TcpListen *c; - if (!list_get(&open_tcp_listen, i, (void **)&c)) { - break; - } - if (c->port == port) { - return c; - } - } - return NULL; -} - -struct TcpConnection *internal_tcp_incoming(u32 src_ip, u16 src_port, - u32 dst_ip, u16 dst_port) { - struct TcpListen *listen = tcp_find_listen(dst_port); - if (!listen) { - return NULL; - } - - struct TcpConnection *con = kcalloc(1, sizeof(struct TcpConnection)); - - int connection_id; - list_add(&open_tcp_connections, con, &connection_id); - - con->current_window_size = 536; - con->outgoing_ip = src_ip; - 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); - relist_init(&con->inflight); - con->max_inflight = 1; - stack_push(&listen->incoming_connections, con); - return con; -} - int tcp_sync_buffer(vfs_fd_t *fd) { struct TcpConnection *con = fd->inode->internal_object; assert(con); - if (con->dead) { + if (TCP_STATE_CLOSED == con->state) { return 0; } @@ -117,21 +79,22 @@ int tcp_sync_buffer(vfs_fd_t *fd) { return 0; } - send_buffer_len = min(tcp_can_send(con), send_buffer_len); - if(0 == send_buffer_len) { - return 0; - } + u32 len = min(tcp_can_send(con), send_buffer_len); - char *send_buffer = kmalloc(send_buffer_len); - assert(ringbuffer_read(rb, send_buffer, send_buffer_len) == send_buffer_len); - send_tcp_packet(con, send_buffer, send_buffer_len); + char *send_buffer = kmalloc(len); + assert(ringbuffer_read(rb, send_buffer, len) == len); + send_tcp_packet(con, send_buffer, len); kfree(send_buffer); - return 1; + if (len < send_buffer_len) { + return 0; + } else { + return 1; + } } void tcp_close(vfs_fd_t *fd) { struct TcpConnection *con = fd->inode->internal_object; - + assert(con); tcp_sync_buffer(fd); tcp_close_connection(con); @@ -140,23 +103,40 @@ void tcp_close(vfs_fd_t *fd) { int tcp_read(u8 *buffer, u64 offset, u64 len, vfs_fd_t *fd) { struct TcpConnection *con = fd->inode->internal_object; assert(con); - if (con->dead) { - return -EBADF; // TODO: Check if this is correct. - } - u32 rc = ringbuffer_read(&con->incoming_buffer, buffer, len); if (0 == rc && len > 0) { + if (TCP_STATE_ESTABLISHED != con->state) { + return 0; + } return -EWOULDBLOCK; } return rc; } +int tcp_has_data(vfs_inode_t *inode) { + struct TcpConnection *con = inode->internal_object; + return !(ringbuffer_isempty(&con->incoming_buffer)); +} + +int tcp_can_write(vfs_inode_t *inode) { + struct TcpConnection *con = inode->internal_object; + if (con->no_delay) { + return (0 != tcp_can_send(con)); + } + return (ringbuffer_unused(&con->outgoing_buffer) > 0) || + (0 != tcp_can_send(con)); +} + int tcp_write(u8 *buffer, u64 offset, u64 len, vfs_fd_t *fd) { (void)offset; struct TcpConnection *con = fd->inode->internal_object; assert(con); - if (con->dead) { - return -EBADF; // TODO: Check if this is correct. + if (TCP_STATE_ESTABLISHED != con->state) { + return -ENOTCONN; + } + + if (!tcp_can_write(fd->inode)) { + return -EWOULDBLOCK; } len = min(len, tcp_can_send(con)); @@ -174,32 +154,17 @@ int tcp_write(u8 *buffer, u64 offset, u64 len, vfs_fd_t *fd) { struct ringbuffer *rb = &con->outgoing_buffer; if (ringbuffer_unused(rb) < len) { if (!tcp_sync_buffer(fd)) { - return -EWOULDBLOCK; + return 0; } if (!send_tcp_packet(con, buffer, len)) { return -EWOULDBLOCK; } - len = 0; } else { assert(ringbuffer_write(rb, buffer, len) == len); } return len; } -int tcp_has_data(vfs_inode_t *inode) { - struct TcpConnection *con = inode->internal_object; - return !(ringbuffer_isempty(&con->incoming_buffer)); -} - -int tcp_can_write(vfs_inode_t *inode) { - struct TcpConnection *con = inode->internal_object; - if (con->no_delay) { - return (0 != tcp_can_send(con)); - } - return (ringbuffer_unused(&con->outgoing_buffer) > 0) || - (0 != tcp_can_send(con)); -} - int udp_recvfrom(vfs_fd_t *fd, void *buffer, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) { struct UdpConnection *con = fd->inode->internal_object; @@ -270,7 +235,6 @@ int udp_has_data(vfs_inode_t *inode) { void udp_close(vfs_fd_t *fd) { struct UdpConnection *con = fd->inode->internal_object; con->dead = 1; - ringbuffer_free(&con->incoming_buffer); return; } @@ -308,34 +272,46 @@ int udp_connect(vfs_fd_t *fd, const struct sockaddr *addr, socklen_t addrlen) { } int tcp_connect(vfs_fd_t *fd, const struct sockaddr *addr, socklen_t addrlen) { + struct TcpConnection *con = fd->inode->internal_object; + assert(AF_INET == addr->sa_family); const struct sockaddr_in *in_addr = (const struct sockaddr_in *)addr; - struct TcpConnection *con = kcalloc(1, sizeof(struct TcpConnection)); - if (!con) { - return -ENOMEM; - } + con->state = TCP_STATE_LISTEN; con->incoming_port = 1337; // TODO con->outgoing_ip = in_addr->sin_addr.s_addr; con->outgoing_port = ntohs(in_addr->sin_port); - con->current_window_size = 536; + + con->max_seg = 1; + + con->rcv_wnd = 4096; + con->rcv_nxt = 0; + con->rcv_adv = 0; + + con->snd_una = 0; + con->snd_nxt = 0; + con->snd_max = 0; + con->snd_wnd = 0; + con->sent_ack = 0; ringbuffer_init(&con->incoming_buffer, 8192); ringbuffer_init(&con->outgoing_buffer, 8192); + con->snd_wnd = ringbuffer_unused(&con->incoming_buffer); list_add(&open_tcp_connections, con, NULL); - relist_init(&con->inflight); - con->max_inflight = 1; - tcp_send_syn(con); + con->state = TCP_STATE_SYN_SENT; + tcp_send_empty_payload(con, SYN); for (;;) { - tcp_wait_reply(con); - if (con->dead) { // Port is probably closed + switch_task(); + if (TCP_STATE_CLOSED == con->state) { return -ECONNREFUSED; } - if (0 != con->handshake_state) { + if (TCP_STATE_ESTABLISHED == con->state) { break; } + assert(TCP_STATE_SYN_SENT == con->state || + TCP_STATE_ESTABLISHED == con->state); } fd->inode->_has_data = tcp_has_data; @@ -519,21 +495,7 @@ int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { FS_TYPE_UNIX_SOCKET); return 0; } else if (AF_INET == s->domain) { - struct sockaddr_in *in = (struct sockaddr_in *)addr; - - struct TcpListen *tcp_listen = kmalloc(sizeof(struct TcpListen)); - if (!tcp_listen) { - return -ENOMEM; - } - tcp_listen->ip = in->sin_addr.s_addr; - tcp_listen->port = ntohs(in->sin_port); - stack_init(&tcp_listen->incoming_connections); - - s->object = tcp_listen; - - inode->_has_data = tcp_listen_has_data; - - list_add(&open_tcp_listen, tcp_listen, NULL); + assert(0); return 0; } ASSERT_NOT_REACHED; @@ -566,6 +528,31 @@ void socket_close(vfs_fd_t *fd) { fd->inode->is_open = 0; } +int tcp_create_fd() { + struct TcpConnection *con = kmalloc(sizeof(struct TcpConnection)); + if (!con) { + return -ENOMEM; + } + con->state = TCP_STATE_CLOSED; + + 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); + if (!inode) { + kfree(con); + return -ENOMEM; + } + int fd = vfs_create_fd(O_RDWR, 0, 0 /*is_tty*/, inode, NULL); + if (fd < 0) { + kfree(con); + kfree(inode); + return fd; + } + return fd; +} + int socket(int domain, int type, int protocol) { int rc = 0; vfs_inode_t *inode = NULL; @@ -612,20 +599,15 @@ int socket(int domain, int type, int protocol) { } if (AF_INET == domain) { int is_udp = (SOCK_DGRAM == type); - - void *connect_handler = NULL; - if (is_udp) { - connect_handler = udp_connect; - } else { - connect_handler = tcp_connect; + if (!is_udp) { + return tcp_create_fd(); } 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*/, - connect_handler); + NULL /*truncate*/, NULL /*stat*/, NULL /*send_signal*/, udp_connect); if (!inode) { rc = -ENOMEM; goto socket_error; |