summaryrefslogtreecommitdiff
path: root/kernel/socket.c
diff options
context:
space:
mode:
authorAnton Kling <anton@kling.gg>2024-07-04 23:03:16 +0200
committerAnton Kling <anton@kling.gg>2024-07-05 12:46:50 +0200
commit6bf371cc35c11890ab18c32aabd11bf8a816e574 (patch)
tree00df8f66ec65fc8a59aa315ef90be91cadd64cb5 /kernel/socket.c
parent59893c116e9e4e5dd04c24c0ba2fd06fe1936500 (diff)
TCP: Add back support for listening on a socket
Diffstat (limited to 'kernel/socket.c')
-rw-r--r--kernel/socket.c164
1 files changed, 135 insertions, 29 deletions
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;