summaryrefslogtreecommitdiff
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
parent59893c116e9e4e5dd04c24c0ba2fd06fe1936500 (diff)
TCP: Add back support for listening on a socket
-rw-r--r--kernel/cpu/syscall.c2
-rw-r--r--kernel/fs/ext2.c4
-rw-r--r--kernel/fs/shm.c9
-rw-r--r--kernel/fs/tmpfs.c4
-rw-r--r--kernel/fs/vfs.c6
-rw-r--r--kernel/fs/vfs.h6
-rw-r--r--kernel/network/tcp.c16
-rw-r--r--kernel/socket.c164
-rw-r--r--kernel/socket.h5
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);