From 7d2ab3a71f4bda9d8ee997764d98b29e13a902c5 Mon Sep 17 00:00:00 2001
From: Anton Kling <anton@kling.gg>
Date: Mon, 29 Apr 2024 18:00:20 +0200
Subject: Kernel/Socket: Move sockets back to being file descriptors

---
 kernel/Makefile                    |   2 +-
 kernel/cpu/isr.s                   |   2 +-
 kernel/cpu/syscall.c               |  91 +++++----
 kernel/drivers/keyboard.c          |   2 +-
 kernel/fs/vfs.c                    |   2 +-
 kernel/includes/syscalls.h         |   5 -
 kernel/init/kernel.c               |   2 +
 kernel/lib/ringbuffer.c            |  17 ++
 kernel/lib/ringbuffer.h            |   3 +
 kernel/lib/stack.c                 |   4 +
 kernel/lib/stack.h                 |   1 +
 kernel/network/tcp.c               |  14 +-
 kernel/network/tcp.h               |   2 +-
 kernel/sched/scheduler.c           |  31 ---
 kernel/sched/scheduler.h           |   3 -
 kernel/socket.c                    | 384 ++++++++++++++++++++++---------------
 kernel/socket.h                    |  19 +-
 userland/libc/Makefile             |   4 +-
 userland/libc/include/math.h       |  14 ++
 userland/libc/include/signal.h     |   1 +
 userland/libc/include/sys/socket.h |   1 +
 userland/libc/include/syscall.h    |   1 +
 22 files changed, 353 insertions(+), 252 deletions(-)

diff --git a/kernel/Makefile b/kernel/Makefile
index 240f7df..149b1bc 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 syscalls/ppoll.o syscalls/ftruncate.o kubsan.o syscalls/mmap.o drivers/serial.o syscalls/accept.o syscalls/bind.o syscalls/socket.o socket.o poll.o fs/fifo.o hashmap/hashmap.o fs/shm.o syscalls/shm.o elf.o ksbrk.o sched/scheduler.o syscalls/fstat.o libc/string/copy.o drivers/mouse.o libc/string/strlcpy.o libc/string/strcat.o drivers/vbe.o syscalls/msleep.o syscalls/uptime.o syscalls/mkdir.o drivers/pci.o drivers/rtl8139.o network/ethernet.o network/arp.o network/bytes.o network/ipv4.o network/udp.o syscalls/recvfrom.o math.o syscalls/sendto.o signal.o syscalls/kill.o syscalls/sigaction.o network/tcp.o drivers/ahci.o crypto/xoshiro256plusplus/xoshiro256plusplus.o syscalls/chdir.o syscalls/getcwd.o syscalls/isatty.o syscalls/randomfill.o syscalls/open.o syscalls/write.o syscalls/pwrite.o syscalls/port.o syscalls/map_frames.o syscalls/virtual_to_physical.o syscalls/install_irq.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 queue.o syscalls/queue.o syscalls/munmap.o syscalls/open_process.o syscalls/lseek.o lib/ringbuffer.o lib/relist.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 syscalls/ppoll.o syscalls/ftruncate.o kubsan.o syscalls/mmap.o drivers/serial.o syscalls/accept.o syscalls/bind.o syscalls/socket.o socket.o poll.o fs/fifo.o hashmap/hashmap.o fs/shm.o syscalls/shm.o elf.o ksbrk.o sched/scheduler.o syscalls/fstat.o libc/string/copy.o drivers/mouse.o libc/string/strlcpy.o libc/string/strcat.o drivers/vbe.o syscalls/msleep.o syscalls/uptime.o syscalls/mkdir.o drivers/pci.o drivers/rtl8139.o network/ethernet.o network/arp.o network/bytes.o network/ipv4.o network/udp.o syscalls/recvfrom.o math.o syscalls/sendto.o signal.o syscalls/kill.o syscalls/sigaction.o network/tcp.o drivers/ahci.o crypto/xoshiro256plusplus/xoshiro256plusplus.o syscalls/chdir.o syscalls/getcwd.o syscalls/isatty.o syscalls/randomfill.o syscalls/open.o syscalls/write.o syscalls/pwrite.o syscalls/port.o syscalls/map_frames.o syscalls/virtual_to_physical.o syscalls/install_irq.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 syscalls/munmap.o syscalls/open_process.o syscalls/lseek.o lib/ringbuffer.o lib/relist.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/isr.s b/kernel/cpu/isr.s
index 819b22b..9fca13c 100644
--- a/kernel/cpu/isr.s
+++ b/kernel/cpu/isr.s
@@ -32,7 +32,7 @@ ISR_NOERRCODE 9
 ISR_NOERRCODE 10
 ISR_NOERRCODE 11
 ISR_NOERRCODE 12
-ISR_NOERRCODE 13
+ISR_ERRCODE 13
 ISR_ERRCODE 14
 ISR_NOERRCODE 15
 ISR_NOERRCODE 16
diff --git a/kernel/cpu/syscall.c b/kernel/cpu/syscall.c
index 3765a84..84faa16 100644
--- a/kernel/cpu/syscall.c
+++ b/kernel/cpu/syscall.c
@@ -140,49 +140,64 @@ int syscall_openpty(SYS_OPENPTY_PARAMS *args) {
                  args->winp);
 }
 
-u32 syscall_tcp_connect(u32 ip, u16 port, int *error) {
-  // TODO: Make sure error is a user address
-  return tcp_connect_ipv4(ip, port, error);
-}
-
-int syscall_tcp_write(u32 socket, const u8 *buffer, u32 len, u64 *out) {
-  // TODO: Make sure out is a user address
-  return tcp_write(socket, buffer, len, out);
-}
-
-int syscall_tcp_read(u32 socket, u8 *buffer, u32 buffer_size, u64 *out) {
-  // TODO: Make sure out is a user address
-  return tcp_read(socket, buffer, buffer_size, out);
+int syscall_connect(int sockfd, const struct sockaddr *addr,
+                    socklen_t addrlen) {
+  return connect(sockfd, addr, addrlen);
 }
 
 int (*syscall_functions[])() = {
-    (void(*))syscall_open,         (void(*))syscall_mread,
-    (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_outw,
-    (void(*))syscall_inl,          (void(*))syscall_outl,
-    (void(*))syscall_map_frames,   (void(*))syscall_virtual_to_physical,
-    (void(*))syscall_install_irq,  (void(*))syscall_tmp_handle_packet,
-    (void(*))syscall_tcp_connect,  (void(*))syscall_tcp_write,
-    (void(*))syscall_tcp_read,
-    (void(*))syscall_queue_create, (void(*))syscall_queue_add,
-    (void(*))syscall_queue_wait,   (void(*))syscall_munmap,
+    (void(*))syscall_open,
+    (void(*))syscall_mread,
+    (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_outw,
+    (void(*))syscall_inl,
+    (void(*))syscall_outl,
+    (void(*))syscall_map_frames,
+    (void(*))syscall_virtual_to_physical,
+    (void(*))syscall_install_irq,
+    (void(*))syscall_tmp_handle_packet,
+    (void(*))NULL,
+    (void(*))NULL,
+    (void(*))NULL,
+    (void(*))NULL,
+    (void(*))NULL,
+    (void(*))NULL,
+    (void(*))syscall_munmap,
     (void(*))syscall_open_process,
     (void(*))syscall_lseek,
+    (void(*))syscall_connect,
 };
 
 void int_syscall(reg_t *r);
diff --git a/kernel/drivers/keyboard.c b/kernel/drivers/keyboard.c
index 770c8c5..a120788 100644
--- a/kernel/drivers/keyboard.c
+++ b/kernel/drivers/keyboard.c
@@ -5,9 +5,9 @@
 #include <fs/devfs.h>
 #include <fs/fifo.h>
 #include <fs/vfs.h>
+#include <lib/ringbuffer.h>
 #include <sched/scheduler.h>
 #include <typedefs.h>
-#include <lib/ringbuffer.h>
 
 #define PS2_REG_DATA 0x60
 #define PS2_REG_STATUS 0x64
diff --git a/kernel/fs/vfs.c b/kernel/fs/vfs.c
index 9312c2a..cd3f854 100644
--- a/kernel/fs/vfs.c
+++ b/kernel/fs/vfs.c
@@ -340,7 +340,7 @@ int vfs_pmread(int fd, void *buf, u64 count, int blocking, u64 offset) {
     return -EBADF;
   }
   int rc = raw_vfs_pread(vfs_fd, buf, count, offset);
-  if (-EAGAIN == rc && count > 0) {
+  if ((-EAGAIN == rc || -EWOULDBLOCK == rc) && count > 0) {
     if (!(vfs_fd->flags & O_NONBLOCK) && blocking) {
       struct pollfd fds;
       do {
diff --git a/kernel/includes/syscalls.h b/kernel/includes/syscalls.h
index 6945c21..2fabb2b 100644
--- a/kernel/includes/syscalls.h
+++ b/kernel/includes/syscalls.h
@@ -1,5 +1,4 @@
 #include <fs/vfs.h>
-#include <queue.h>
 #include <signal.h>
 #include <socket.h>
 #include <stddef.h>
@@ -13,10 +12,6 @@ u32 syscall_inl(u16 port);
 void syscall_outl(u16 port, u32 l);
 int syscall_open_process(int pid);
 
-int syscall_queue_create(u32 *id);
-int syscall_queue_add(u32 queue_id, struct event *ev, u32 size);
-int syscall_queue_wait(u32 queue_id);
-
 int syscall_ipc_register_endpoint(u32 endpoint);
 int syscall_ipc_read(u8 *buffer, u32 length, u32 *sender_pid);
 int syscall_ipc_write(int ipc_id, u8 *buffer, u32 length);
diff --git a/kernel/init/kernel.c b/kernel/init/kernel.c
index 2b96359..0a2243d 100644
--- a/kernel/init/kernel.c
+++ b/kernel/init/kernel.c
@@ -85,6 +85,8 @@ void kernel_main(u32 kernel_end, unsigned long magic, unsigned long addr,
   install_keyboard();
   klog("PS2 Keyboard driver installed", LOG_SUCCESS);
 
+global_socket_init();
+
   vfs_mount("/dev", devfs_mount());
   assert(ahci_init());
   vfs_inode_t *ext2_mount_point = ext2_mount();
diff --git a/kernel/lib/ringbuffer.c b/kernel/lib/ringbuffer.c
index 66dd17e..9caf555 100644
--- a/kernel/lib/ringbuffer.c
+++ b/kernel/lib/ringbuffer.c
@@ -16,6 +16,23 @@ int ringbuffer_init(struct ringbuffer *rb, u32 buffer_size) {
   return 1;
 }
 
+u32 ringbuffer_used(const struct ringbuffer *rb) {
+  if (rb->write_ptr < rb->read_ptr) {
+    u32 c = rb->buffer_size - rb->read_ptr;
+    c += rb->write_ptr;
+    return c;
+  }
+  return rb->write_ptr - rb->read_ptr;
+}
+
+u32 ringbuffer_capacity(const struct ringbuffer *rb) {
+  return rb->buffer_size - 1;
+}
+
+u32 ringbuffer_unused(const struct ringbuffer *rb) {
+  return ringbuffer_capacity(rb) - ringbuffer_used(rb);
+}
+
 u32 ringbuffer_write(struct ringbuffer *rb, const u8 *buffer, u32 len) {
   const u32 orig_len = len;
   for (; len > 0;) {
diff --git a/kernel/lib/ringbuffer.h b/kernel/lib/ringbuffer.h
index 3ebc507..d6e699a 100644
--- a/kernel/lib/ringbuffer.h
+++ b/kernel/lib/ringbuffer.h
@@ -14,6 +14,9 @@ u32 ringbuffer_write(struct ringbuffer *rb, const u8 *buffer, u32 len);
 u32 ringbuffer_read(struct ringbuffer *rb, u8 *buffer, u32 len);
 int ringbuffer_isempty(const struct ringbuffer *rb);
 void ringbuffer_free(struct ringbuffer *rb);
+u32 ringbuffer_used(const struct ringbuffer *rb);
+u32 ringbuffer_capacity(const struct ringbuffer *rb);
+u32 ringbuffer_unused(const struct ringbuffer *rb);
 #ifdef KERNEL_TEST
 void ringbuffer_test(void);
 #endif // KERNEL_TEST
diff --git a/kernel/lib/stack.c b/kernel/lib/stack.c
index 7283b35..7c44193 100644
--- a/kernel/lib/stack.c
+++ b/kernel/lib/stack.c
@@ -7,6 +7,10 @@ void stack_init(struct stack *s) {
   s->head = NULL;
 }
 
+int stack_isempty(const struct stack *s) {
+  return (NULL == s->head);
+}
+
 // 1 = Success
 // 0 = Failure
 int stack_push(struct stack *s, void *data) {
diff --git a/kernel/lib/stack.h b/kernel/lib/stack.h
index f47fe66..09fff66 100644
--- a/kernel/lib/stack.h
+++ b/kernel/lib/stack.h
@@ -13,6 +13,7 @@ struct stack {
 };
 
 void stack_init(struct stack *s);
+int stack_isempty(const struct stack *s);
 int stack_push(struct stack *s, void *data);
 void *stack_pop(struct stack *s);
 #endif
diff --git a/kernel/network/tcp.c b/kernel/network/tcp.c
index 8740a63..39b8d7c 100644
--- a/kernel/network/tcp.c
+++ b/kernel/network/tcp.c
@@ -121,6 +121,10 @@ void tcp_send_empty_payload(struct TcpConnection *con, u8 flags) {
   send_ipv4_packet((ipv4_t){.d = con->outgoing_ip}, 6, send_buffer, send_len);
 }
 
+void tcp_close_connection(struct TcpConnection *con) {
+  tcp_send_empty_payload(con, FIN | ACK);
+}
+
 void tcp_send_ack(struct TcpConnection *con) {
   tcp_send_empty_payload(con, ACK);
 }
@@ -170,7 +174,6 @@ void handle_tcp(ipv4_t src_ip, const u8 *payload, u32 payload_length) {
   u8 flags = header->flags;
 
   u16 src_port = htons(n_src_port);
-  (void)src_port;
   u16 dst_port = htons(n_dst_port);
   u32 seq_num = htonl(n_seq_num);
   u32 ack_num = htonl(n_ack_num);
@@ -182,10 +185,12 @@ void handle_tcp(ipv4_t src_ip, const u8 *payload, u32 payload_length) {
     assert(con);
     con->ack = seq_num + 1;
     tcp_send_empty_payload(con, SYN | ACK);
+    con->seq++;
     return;
   }
 
-  struct TcpConnection *incoming_connection = tcp_find_connection(dst_port);
+  struct TcpConnection *incoming_connection =
+      tcp_find_connection(src_ip, src_port, dst_port);
   if (!incoming_connection) {
     kprintf("unable to find open port for incoming connection\n");
   }
@@ -214,8 +219,8 @@ void handle_tcp(ipv4_t src_ip, const u8 *payload, u32 payload_length) {
     u16 tcp_payload_length = payload_length - header->data_offset * sizeof(u32);
     if (tcp_payload_length > 0) {
       const u8 *tcp_payload = payload + header->data_offset * sizeof(u32);
-      u32 len = ringbuffer_write(&incoming_connection->buffer, tcp_payload,
-                                 tcp_payload_length);
+      u32 len = ringbuffer_write(&incoming_connection->incoming_buffer,
+                                 tcp_payload, tcp_payload_length);
       assert(len == tcp_payload_length);
       incoming_connection->ack += len;
       tcp_send_ack(incoming_connection);
@@ -224,6 +229,7 @@ void handle_tcp(ipv4_t src_ip, const u8 *payload, u32 payload_length) {
       incoming_connection->ack++;
 
       tcp_send_empty_payload(incoming_connection, FIN | ACK);
+      incoming_connection->seq++;
 
       incoming_connection->dead = 1; // FIXME: It should wait for a ACK
                                      // of the FIN before the connection
diff --git a/kernel/network/tcp.h b/kernel/network/tcp.h
index 0c53535..1e292b3 100644
--- a/kernel/network/tcp.h
+++ b/kernel/network/tcp.h
@@ -5,4 +5,4 @@ void tcp_wait_reply(struct TcpConnection *con);
 void handle_tcp(ipv4_t src_ip, const u8 *payload, u32 payload_length);
 void send_tcp_packet(struct TcpConnection *con, const u8 *payload,
                      u16 payload_length);
-void tcp_close_connection(struct INCOMING_TCP_CONNECTION *s);
+void tcp_close_connection(struct TcpConnection *con);
diff --git a/kernel/sched/scheduler.c b/kernel/sched/scheduler.c
index 639dd05..9a241ac 100644
--- a/kernel/sched/scheduler.c
+++ b/kernel/sched/scheduler.c
@@ -7,7 +7,6 @@
 #include <errno.h>
 #include <fs/vfs.h>
 #include <interrupts.h>
-#include <queue.h>
 #include <signal.h>
 
 // FIXME: Use the process_t struct instead or keep this contained in it.
@@ -160,11 +159,6 @@ process_t *create_process(process_t *p, u32 esp, u32 eip) {
   list_init(&r->write_list);
   list_init(&r->disconnect_list);
 
-  list_init(&r->tcp_sockets);
-  list_init(&r->tcp_listen);
-
-  list_init(&r->event_queue);
-
   if (esp) {
     esp -= 4;
     insert_eip_on_stack(r->cr3->physical_address, esp, eip);
@@ -209,9 +203,6 @@ void free_process(process_t *p) {
   list_free(&p->read_list);
   list_free(&p->write_list);
   list_free(&p->disconnect_list);
-  list_free(&p->tcp_sockets);
-  list_free(&p->tcp_listen);
-  list_free(&p->event_queue);
   relist_free(&p->file_descriptors);
   kfree(p->tcb);
 
@@ -428,28 +419,6 @@ int is_halted(process_t *process) {
     }
   }
 
-  int queue_block = 1;
-  int wait_empty = 1;
-  for (int i = 0;; i++) {
-    struct event_queue *q;
-    if (!list_get(&process->event_queue, i, (void **)&q)) {
-      break;
-    }
-    int is_empty;
-    int rc = queue_should_block(q, &is_empty);
-    if (is_empty) {
-      wait_empty = 0;
-      continue;
-    }
-    if (0 == rc) {
-      queue_block = 0;
-    }
-  }
-  if (!queue_block && !wait_empty) {
-    kprintf("skip because queue_wait has data\n");
-    return 0;
-  }
-
   int fd_empty;
   if (isset_fdhalt(process, &fd_empty) && !fd_empty) {
     return 1;
diff --git a/kernel/sched/scheduler.h b/kernel/sched/scheduler.h
index feb6aa5..7a8bf0c 100644
--- a/kernel/sched/scheduler.h
+++ b/kernel/sched/scheduler.h
@@ -68,9 +68,6 @@ struct Process {
   struct list write_list;
   struct list disconnect_list;
 
-  struct list tcp_sockets;
-  struct list tcp_listen;
-
   struct list event_queue;
 
   struct stack restore_context_stack;
diff --git a/kernel/socket.c b/kernel/socket.c
index e0c3f35..fbc0648 100644
--- a/kernel/socket.c
+++ b/kernel/socket.c
@@ -9,6 +9,14 @@
 #include <sched/scheduler.h>
 #include <socket.h>
 
+struct list open_tcp_connections;
+struct list open_tcp_listen;
+
+void global_socket_init(void) {
+  list_init(&open_tcp_connections);
+  list_init(&open_tcp_listen);
+}
+
 OPEN_UNIX_SOCKET *un_sockets[100] = {0};
 
 void gen_ipv4(ipv4_t *ip, u8 i1, u8 i2, u8 i3, u8 i4) {
@@ -18,44 +26,29 @@ void gen_ipv4(ipv4_t *ip, u8 i1, u8 i2, u8 i3, u8 i4) {
   ip->a[3] = i4;
 }
 
-struct TcpConnection *tcp_find_connection(u16 port) {
-  process_t *p = current_task;
-  p = p->next;
-  for (int i = 0; i < 100; i++, p = p->next) {
-    if (!p) {
-      p = ready_queue;
+struct TcpConnection *tcp_find_connection(ipv4_t src_ip, u16 src_port,
+                                          u16 dst_port) {
+  (void)src_ip;
+  for (int i = 0;; i++) {
+    struct TcpConnection *c;
+    if (!list_get(&open_tcp_connections, i, (void **)&c)) {
+      break;
     }
-    struct list *connections = &p->tcp_sockets;
-    for (int i = 0;; i++) {
-      struct TcpConnection *c;
-      if (!list_get(connections, i, (void **)&c)) {
-        break;
-      }
-      if (c->incoming_port == port) {
-        return c;
-      }
+    if (c->incoming_port == dst_port && c->outgoing_port == src_port) {
+      return c;
     }
   }
   return NULL;
 }
 
 struct TcpListen *tcp_find_listen(u16 port) {
-  process_t *p = current_task;
-  process_t *s = p;
-  p = p->next;
-  for (; p != s; p = p->next) {
-    if (!p) {
-      p = ready_queue;
+  for (int i = 0;; i++) {
+    struct TcpListen *c;
+    if (!list_get(&open_tcp_listen, i, (void **)&c)) {
+      break;
     }
-    struct list *listen_list = &p->tcp_listen;
-    for (int i = 0;; i++) {
-      struct TcpListen *c;
-      if (!list_get(listen_list, i, (void **)&c)) {
-        break;
-      }
-      if (c->port == port) {
-        return c;
-      }
+    if (c->port == port) {
+      return c;
     }
   }
   return NULL;
@@ -71,134 +64,125 @@ struct TcpConnection *internal_tcp_incoming(u32 src_ip, u16 src_port,
   struct TcpConnection *con = kcalloc(1, sizeof(struct TcpConnection));
 
   int connection_id;
-  struct list *connections = &current_task->tcp_sockets;
-  list_add(connections, con, &connection_id);
+  list_add(&open_tcp_connections, con, &connection_id);
 
   con->outgoing_ip = src_ip;
   con->outgoing_port = src_port;
-  //  con->incoming_ip = dst_ip;
-  con->incoming_port = dst_port; // FIXME: Should be different for each
-                                 // connection
+  con->incoming_ip = dst_ip;
+  con->incoming_port = dst_port;
 
-  ringbuffer_init(&con->buffer, 8192);
-  stack_push(&listen->incoming_connections, (void *)connection_id);
+  ringbuffer_init(&con->incoming_buffer, 8192);
+  ringbuffer_init(&con->outgoing_buffer, 8192);
+  stack_push(&listen->incoming_connections, con);
   return con;
 }
 
-u32 tcp_listen_ipv4(u32 ip, u16 port, int *error) {
-  *error = 0;
+int tcp_sync_buffer(vfs_fd_t *fd) {
+  struct TcpConnection *con = fd->inode->internal_object;
+  assert(con);
+  if (con->dead) {
+    return -EBADF; // TODO: Check if this is correct.
+  }
+
+  struct ringbuffer *rb = &con->outgoing_buffer;
+  u32 send_buffer_len = ringbuffer_used(rb);
+  if (0 == send_buffer_len) {
+    return 0;
+  }
+  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);
+  kfree(send_buffer);
+  return 0;
+}
+
+void tcp_close(vfs_fd_t *fd) {
+  struct TcpConnection *con = fd->inode->internal_object;
 
-  struct TcpListen *listener = kcalloc(1, sizeof(struct TcpListen));
-  listener->ip = ip;
-  listener->port = port;
-  stack_init(&listener->incoming_connections);
+  tcp_sync_buffer(fd);
 
-  struct list *listen_list = &current_task->tcp_listen;
-  int index;
-  list_add(listen_list, listener, &index);
-  return index;
+  tcp_close_connection(con);
 }
 
-struct TcpConnection *tcp_get_connection(u32 socket, process_t *p) {
-  if (!p) {
-    p = current_task;
+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.
   }
-  const struct list *connections = &p->tcp_sockets;
-  struct TcpConnection *con;
-  if (!list_get(connections, socket, (void **)&con)) {
-    return NULL;
+
+  u32 rc = ringbuffer_read(&con->incoming_buffer, buffer, len);
+  if (0 == rc && len > 0) {
+    return -EWOULDBLOCK;
   }
-  return con;
+  return rc;
 }
 
-u32 tcp_accept(u32 listen_socket, int *error) {
-  *error = 0;
-  struct list *listen_list = &current_task->tcp_listen;
-  struct TcpListen *l;
-  if (!list_get(listen_list, listen_socket, (void **)&l)) {
-    *error = 1;
-    return 0;
+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.
   }
-  for (;;) {
-    // TODO: halt the process
-    if (NULL != l->incoming_connections.head) {
-      void *out = stack_pop(&l->incoming_connections);
-      return (u32)out; // TODO: Should a pointer store a u32?
-    }
+
+  struct ringbuffer *rb = &con->outgoing_buffer;
+  if (ringbuffer_unused(rb) < len) {
+    tcp_sync_buffer(fd);
+    send_tcp_packet(con, buffer, len);
+    len = 0;
+  } else {
+    assert(ringbuffer_write(rb, buffer, len) == len);
   }
-  ASSERT_NOT_REACHED;
+  return len;
+}
+
+int tcp_has_data(vfs_inode_t *inode) {
+  struct TcpConnection *con = inode->internal_object;
+  return !(ringbuffer_isempty(&con->incoming_buffer));
 }
 
-u32 tcp_connect_ipv4(u32 ip, u16 port, int *error) {
-  struct list *connections = &current_task->tcp_sockets;
-  *error = 0;
+int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
+  vfs_fd_t *fd = get_vfs_fd(sockfd, NULL);
+  assert(fd);
+
+  if (fd->inode->internal_object) {
+    return -EISCONN;
+  }
 
+  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));
-  int index;
-  list_add(connections, con, &index);
+  if (!con) {
+    return -ENOMEM;
+  }
 
   con->incoming_port = 1337; // TODO
-  con->outgoing_ip = ip;
-  con->outgoing_port = port;
+  con->outgoing_ip = in_addr->sin_addr.s_addr;
+  con->outgoing_port = in_addr->sin_port;
 
-  ringbuffer_init(&con->buffer, 8192);
+  ringbuffer_init(&con->incoming_buffer, 8192);
+  ringbuffer_init(&con->outgoing_buffer, 8192);
+  list_add(&open_tcp_connections, con, NULL);
 
   tcp_send_syn(con);
 
   for (;;) {
     tcp_wait_reply(con);
     if (con->dead) { // Port is probably closed
-      *error = 1;
-      return 0;
+      return -ECONNREFUSED;
     }
     if (0 != con->handshake_state) {
       break;
     }
   }
 
-  return index;
-}
-
-int tcp_write(u32 socket, const u8 *buffer, u64 len, u64 *out) {
-  if (out) {
-    *out = 0;
-  }
-  struct TcpConnection *con = tcp_get_connection(socket, NULL);
-  if (!con) {
-    return 0;
-  }
-  if (con->dead) {
-    return 0;
-  }
-
-  send_tcp_packet(con, buffer, len);
-  if (out) {
-    *out = len;
-  }
-  return 1;
-}
-
-int tcp_read(u32 socket, u8 *buffer, u64 buffer_size, u64 *out) {
-  if (out) {
-    *out = 0;
-  }
-  struct TcpConnection *con = tcp_get_connection(socket, NULL);
-  if (!con) {
-    return 0;
-  }
-  if (con->dead) {
-    return 0;
-  }
-
-  u32 len = ringbuffer_read(&con->buffer, buffer, buffer_size);
-  if (out) {
-    *out = len;
-  }
-  return 1;
-}
-
-void tcp_close(u32 socket) {
-  assert(NULL);
+  fd->inode->_has_data = tcp_has_data;
+  fd->inode->write = tcp_write;
+  fd->inode->read = tcp_read;
+  fd->inode->close = tcp_close;
+  fd->inode->internal_object = con;
+  return 0;
 }
 
 int uds_open(const char *path) {
@@ -238,6 +222,12 @@ int uds_open(const char *path) {
   return fd[0];
 }
 
+int tcp_listen_has_data(vfs_inode_t *inode) {
+  const SOCKET *s = (SOCKET *)inode->internal_object;
+  const struct TcpListen *tcp_listen = s->object;
+  return !stack_isempty(&tcp_listen->incoming_connections);
+}
+
 int accept(int socket, struct sockaddr *address, socklen_t *address_len) {
   (void)address;
   (void)address_len;
@@ -245,25 +235,50 @@ int accept(int socket, struct sockaddr *address, socklen_t *address_len) {
   assert(fd_ptr);
   vfs_inode_t *inode = fd_ptr->inode;
   SOCKET *s = (SOCKET *)inode->internal_object;
+  if (AF_UNIX == s->domain) {
+    for (; NULL == s->incoming_fd;) {
+      // Wait until we have gotten a connection
+      struct pollfd fds[1];
+      fds[0].fd = socket;
+      fds[0].events = POLLIN;
+      fds[0].revents = 0;
+      poll(fds, 1, 0);
+    }
 
-  for (; NULL == s->incoming_fd;) {
-    // Wait until we have gotten a connection
-    struct pollfd fds[1];
-    fds[0].fd = socket;
-    fds[0].events = POLLIN;
-    fds[0].revents = 0;
-    poll(fds, 1, 0);
+    int index;
+    assert(relist_add(&current_task->file_descriptors, s->incoming_fd, &index));
+    assert(1 <= s->incoming_fd->reference_count);
+    s->incoming_fd = NULL;
+    return index;
   }
-
-  int index;
-  assert(relist_add(&current_task->file_descriptors, s->incoming_fd, &index));
-  assert(1 <= s->incoming_fd->reference_count);
-  s->incoming_fd = NULL;
-  //  for (char c; 0 < vfs_pread(s->fifo_fd, &c, 1, 0);)
-  //    ;
-  //  s->ptr_fifo_fd->inode->has_data = 0;
-
-  return index;
+  if (AF_INET == s->domain) {
+    struct TcpListen *tcp_listen = s->object;
+    assert(tcp_listen);
+    if (stack_isempty(&tcp_listen->incoming_connections)) {
+      if (fd_ptr->flags & O_NONBLOCK) {
+        return -EWOULDBLOCK;
+      }
+      struct pollfd fds[1];
+      fds[0].fd = socket;
+      fds[0].events = POLLIN;
+      fds[0].revents = 0;
+      poll(fds, 1, 0);
+    }
+    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,
+        always_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*/);
+    assert(inode);
+    return vfs_create_fd(O_RDWR, 0, 0 /*is_tty*/, inode, NULL);
+  }
+  ASSERT_NOT_REACHED;
+  return 0;
 }
 
 int bind_has_data(vfs_inode_t *inode) {
@@ -286,6 +301,9 @@ int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
   if (!inode) {
     return -EBADF;
   }
+  if (FS_TYPE_UNIX_SOCKET != inode->type) {
+    return -ENOTSOCK;
+  }
   SOCKET *s = (SOCKET *)inode->internal_object;
   if (AF_UNIX == s->domain) {
     struct sockaddr_un *un = (struct sockaddr_un *)addr;
@@ -310,8 +328,25 @@ 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) {
+    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);
+    return 0;
   }
-  return 0;
+  ASSERT_NOT_REACHED;
 }
 
 int socket_has_data(vfs_inode_t *inode) {
@@ -342,29 +377,68 @@ void socket_close(vfs_fd_t *fd) {
 }
 
 int socket(int domain, int type, int protocol) {
+  int rc = 0;
+  vfs_inode_t *inode = NULL;
+  SOCKET *new_socket = NULL;
   if (!(AF_UNIX == domain || AF_INET == domain)) {
-    return -EINVAL;
+    rc = -EINVAL;
+    goto socket_error;
   }
 
-  SOCKET *new_socket = kmalloc(sizeof(SOCKET));
-  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*/);
-
-  vfs_fd_t *fd;
-  int n = vfs_create_fd(O_RDWR | O_NONBLOCK, 0, 0 /*is_tty*/, inode, &fd);
-
+  new_socket = kmalloc(sizeof(SOCKET));
+  if (!new_socket) {
+    rc = -ENOMEM;
+    goto socket_error;
+  }
   new_socket->domain = domain;
   new_socket->type = type;
   new_socket->protocol = protocol;
   new_socket->path = NULL;
   new_socket->incoming_fd = NULL;
+  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*/);
+    if (!inode) {
+      rc = -ENOMEM;
+      goto socket_error;
+    }
+
+    vfs_fd_t *fd;
+    int n = vfs_create_fd(O_RDWR | O_NONBLOCK, 0, 0 /*is_tty*/, inode, &fd);
+    if (n < 0) {
+      rc = n;
+      goto socket_error;
+    }
 
-  new_socket->fifo_file = create_fifo_object();
+    new_socket->fifo_file = create_fifo_object();
 
-  new_socket->ptr_socket_fd = fd;
-  return n;
+    new_socket->ptr_socket_fd = fd;
+    return n;
+  }
+  if (AF_INET == domain) {
+    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*/);
+    if (!inode) {
+      rc = -ENOMEM;
+      goto socket_error;
+    }
+    int n = vfs_create_fd(O_RDWR, 0, 0 /*is_tty*/, inode, NULL);
+    if (n < 0) {
+      rc = n;
+      goto socket_error;
+    }
+    return n;
+  }
+  ASSERT_NOT_REACHED;
+socket_error:
+  kfree(inode);
+  kfree(new_socket);
+  return rc;
 }
diff --git a/kernel/socket.h b/kernel/socket.h
index ad505b8..b542c87 100644
--- a/kernel/socket.h
+++ b/kernel/socket.h
@@ -20,13 +20,6 @@
 #define MSG_WAITALL 1
 
 void gen_ipv4(ipv4_t *ip, u8 i1, u8 i2, u8 i3, u8 i4);
-u32 tcp_connect_ipv4(u32 ip, u16 port, int *error);
-
-u32 tcp_listen_ipv4(u32 ip, u16 port, int *error);
-u32 tcp_accept(u32 listen_socket, int *error);
-
-int tcp_write(u32 socket, const u8 *buffer, u64 len, u64 *out);
-int tcp_read(u32 socket, u8 *buffer, u64 buffer_size, u64 *out);
 
 struct TcpListen {
   u32 ip;
@@ -37,11 +30,13 @@ struct TcpListen {
 struct TcpConnection {
   int dead;
   u16 incoming_port;
+  u32 incoming_ip;
   u32 outgoing_ip;
   u16 outgoing_port;
 
   int unhandled_packet;
-  struct ringbuffer buffer;
+  struct ringbuffer incoming_buffer;
+  struct ringbuffer outgoing_buffer;
 
   u32 seq;
   u32 ack;
@@ -53,7 +48,8 @@ struct TcpConnection *tcp_get_connection(u32 socket, process_t *p);
 struct TcpConnection *internal_tcp_incoming(u32 src_ip, u16 src_port,
                                             u32 dst_ip, u16 dst_port);
 
-struct TcpConnection *tcp_find_connection(u16 port);
+struct TcpConnection *tcp_find_connection(ipv4_t src_ip, u16 src_port,
+                                          u16 dst_port);
 
 typedef struct {
   vfs_fd_t *ptr_socket_fd;
@@ -67,6 +63,8 @@ typedef struct {
   // UNIX socket
   char *path;
   vfs_fd_t *incoming_fd;
+
+  void *object;
 } SOCKET;
 
 typedef struct {
@@ -115,4 +113,7 @@ struct INCOMING_TCP_CONNECTION *
 handle_incoming_tcp_connection(u8 ip[4], u16 n_port, u16 dst_port);
 struct INCOMING_TCP_CONNECTION *get_incoming_tcp_connection(u8 ip[4],
                                                             u16 n_port);
+int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
+void global_socket_init(void);
+u16 tcp_get_free_port(void);
 #endif
diff --git a/userland/libc/Makefile b/userland/libc/Makefile
index 94cf28f..af65a56 100644
--- a/userland/libc/Makefile
+++ b/userland/libc/Makefile
@@ -1,8 +1,8 @@
 CC="i686-sb-gcc"
 AR="i686-sb-ar"
 AS="i686-sb-as"
-CFLAGS = -ggdb -ffreestanding -O2 -Wall -Wextra -pedantic -Werror -Wimplicit-fallthrough -I./include/ -static -I../../include/ -Wno-int-conversion -Wno-unused-parameter
-OBJ=crt0.o libc.o malloc/malloc.o pty.o sys/mman/mmap.o sys/mman/munmap.o memset.o assert.o stdio/snprintf.o stdio/vfprintf.o string/memcpy.o string/memcmp.o string/strcmp.o ubsan.o string/strcpy.o isspace.o stdio/puts.o stdio/putchar.o dirent/opendir.o dirent/readdir.o dirent/closedir.o unistd/getopt.o dirent/scandir.o dirent/alphasort.o stdio/printf.o stdio/vdprintf.o stdio/vprintf.o stdio/dprintf.o stdio/vprintf.o string/strlen.o string/strnlen.o stdio/stdin.o stdio/getchar.o stdio/fgetc.o arpa/inet/htons.o arpa/inet/htonl.o stdio/fread.o stdio/fwrite.o stdio/fopen.o stdio/fclose.o stdio/fseek.o ctype/isascii.o stdio/fprintf.o stdlib/atoi.o stdlib/strtol.o ctype/toupper.o ctype/tolower.o string/strcat.o string/strchr.o string/sscanf.o sys/stat/stat.o stdlib/getenv.o string/strrchr.o stdio/ftell.o stdio/tmpfile.o stdio/fgets.o stdio/feof.o stdio/fscanf.o stdio/ungetc.o string/strncmp.o stdio/fputc.o string/strncpy.o stdio/remove.o stdio/ferror.o stdio/fputs.o stdlib/rand.o stdlib/srand.o unistd/getpid.o stdlib/strtoul.o stdio/fflush.o stdlib/abort.o string/strcspn.o time/localtime.o time/time.o time/clock_gettime.o time/gmtime.o time/strftime.o string/strpbrk.o ctype/isdigit.o ctype/isalpha.o ctype/isxdigit.o ctype/ispunct.o stdio/setvbuf.o stdio/fileno.o stdio/putc.o stdio/sprintf.o stdlib/abs.o string/strspn.o stdlib/qsort.o string/memmove.o setjmp/longjmp.o setjmp/setjmp.o libgen/basename.o string/strdup.o string/strndup.o string/strlcpy.o stdlib/atexit.o stdio/open_memstream.o libgen/dirname.o unistd/unlink.o string/strstr.o string/strcasecmp.o string/strncasecmp.o stdlib/mkstemp.o string/strtok.o unistd/execvp.o unistd/_exit.o ctype/isalnum.o time/ctime_r.o stdlib/strtold.o sys/time/gettimeofday.o stdio/fgetpos.o stdio/fsetpos.o ctype/isprint.o stdlib/system.o stdio/tmpnam.o unistd/msleep.o stdlib/atof.o stdlib/strtod.o stdio/rename.o sys/stat/mkdir.o unistd/uptime.o unistd/ftruncate.o sys/socket/recvfrom.o sys/socket/sendto.o signal/kill.o signal/sigaction.o unistd/chdir.o unistd/getcwd.o stdio/getdelim.o stdio/getline.o unistd/isatty.o sys/socket/listen.o stdlib/realpath.o systemcall.o sys/random/randomfill.o fcntl/open.o unistd/write.o unistd/pwrite.o fcntl/open_process.o tb/sb.o tb/sv.o string/memchr.o stdlib/atol.o stdlib/atoll.o stdlib/strtoll.o sys/stat/fstat.o unistd/lseek.o ctype/isupper.o ctype/islower.o ctype/isblank.o ctype/isgraph.o ctype/iscntrl.o
+CFLAGS = -ggdb -ffreestanding -O0 -Wall -Wextra -pedantic -Werror -Wimplicit-fallthrough -I./include/ -static -I../../include/ -Wno-int-conversion -Wno-unused-parameter
+OBJ=crt0.o libc.o malloc/malloc.o pty.o sys/mman/mmap.o sys/mman/munmap.o memset.o assert.o stdio/snprintf.o stdio/vfprintf.o string/memcpy.o string/memcmp.o string/strcmp.o ubsan.o string/strcpy.o isspace.o stdio/puts.o stdio/putchar.o dirent/opendir.o dirent/readdir.o dirent/closedir.o unistd/getopt.o dirent/scandir.o dirent/alphasort.o stdio/printf.o stdio/vdprintf.o stdio/vprintf.o stdio/dprintf.o stdio/vprintf.o string/strlen.o string/strnlen.o stdio/stdin.o stdio/getchar.o stdio/fgetc.o arpa/inet/htons.o arpa/inet/htonl.o stdio/fread.o stdio/fwrite.o stdio/fopen.o stdio/fclose.o stdio/fseek.o ctype/isascii.o stdio/fprintf.o stdlib/atoi.o stdlib/strtol.o ctype/toupper.o ctype/tolower.o string/strcat.o string/strchr.o string/sscanf.o sys/stat/stat.o stdlib/getenv.o string/strrchr.o stdio/ftell.o stdio/tmpfile.o stdio/fgets.o stdio/feof.o stdio/fscanf.o stdio/ungetc.o string/strncmp.o stdio/fputc.o string/strncpy.o stdio/remove.o stdio/ferror.o stdio/fputs.o stdlib/rand.o stdlib/srand.o unistd/getpid.o stdlib/strtoul.o stdio/fflush.o stdlib/abort.o string/strcspn.o time/localtime.o time/time.o time/clock_gettime.o time/gmtime.o time/strftime.o string/strpbrk.o ctype/isdigit.o ctype/isalpha.o ctype/isxdigit.o ctype/ispunct.o stdio/setvbuf.o stdio/fileno.o stdio/putc.o stdio/sprintf.o stdlib/abs.o string/strspn.o stdlib/qsort.o string/memmove.o setjmp/longjmp.o setjmp/setjmp.o libgen/basename.o string/strdup.o string/strndup.o string/strlcpy.o stdlib/atexit.o stdio/open_memstream.o libgen/dirname.o unistd/unlink.o string/strstr.o string/strcasecmp.o string/strncasecmp.o stdlib/mkstemp.o string/strtok.o unistd/execvp.o unistd/_exit.o ctype/isalnum.o time/ctime_r.o stdlib/strtold.o sys/time/gettimeofday.o stdio/fgetpos.o stdio/fsetpos.o ctype/isprint.o stdlib/system.o stdio/tmpnam.o unistd/msleep.o stdlib/atof.o stdlib/strtod.o stdio/rename.o sys/stat/mkdir.o unistd/uptime.o unistd/ftruncate.o sys/socket/recvfrom.o sys/socket/sendto.o signal/kill.o signal/sigaction.o unistd/chdir.o unistd/getcwd.o stdio/getdelim.o stdio/getline.o unistd/isatty.o sys/socket/listen.o stdlib/realpath.o systemcall.o sys/random/randomfill.o fcntl/open.o unistd/write.o unistd/pwrite.o fcntl/open_process.o tb/sb.o tb/sv.o string/memchr.o stdlib/atol.o stdlib/atoll.o stdlib/strtoll.o sys/stat/fstat.o unistd/lseek.o ctype/isupper.o ctype/islower.o ctype/isblank.o ctype/isgraph.o ctype/iscntrl.o math/ldexp.o sys/socket/connect.o
 all: libc.a
 
 %.o: %.c
diff --git a/userland/libc/include/math.h b/userland/libc/include/math.h
index 9d4f4b4..d85b3a0 100644
--- a/userland/libc/include/math.h
+++ b/userland/libc/include/math.h
@@ -1,2 +1,16 @@
 #define max(_a, _b) ((_a) > (_b) ? (_a) : (_b))
 #define min(_a, _b) ((_a) < (_b) ? (_a) : (_b))
+
+#if 100*__GNUC__+__GNUC_MINOR__ >= 303
+#define NAN       __builtin_nanf("")
+#define INFINITY  __builtin_inff()
+#else
+#define NAN       (0.0f/0.0f)
+#define INFINITY  1e40f
+#endif
+
+#define HUGE_VALF INFINITY
+#define HUGE_VAL  ((double)INFINITY)
+#define HUGE_VALL ((long double)INFINITY)
+
+double ldexp(double x, int exp);
diff --git a/userland/libc/include/signal.h b/userland/libc/include/signal.h
index a241015..42702b2 100644
--- a/userland/libc/include/signal.h
+++ b/userland/libc/include/signal.h
@@ -13,6 +13,7 @@
 #define SIGKILL 9
 #define SIGFPE 10
 #define SIGTERM 15
+#define SIG_DFL 16
 
 typedef int pid_t;
 typedef int sigset_t;
diff --git a/userland/libc/include/sys/socket.h b/userland/libc/include/sys/socket.h
index 7a2cc23..fb874a1 100644
--- a/userland/libc/include/sys/socket.h
+++ b/userland/libc/include/sys/socket.h
@@ -8,3 +8,4 @@ size_t recvfrom(int socket, void *buffer, size_t length, int flags,
 size_t sendto(int socket, const void *message, size_t length, int flags,
                const struct sockaddr *dest_addr, socklen_t dest_len);
 int listen(int socket, int backlog);
+int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
diff --git a/userland/libc/include/syscall.h b/userland/libc/include/syscall.h
index 201ff3d..f318955 100644
--- a/userland/libc/include/syscall.h
+++ b/userland/libc/include/syscall.h
@@ -59,6 +59,7 @@
 #define SYS_MUNMAP 48
 #define SYS_OPEN_PROCESS 49
 #define SYS_LSEEK 50
+#define SYS_CONNECT 51
 
 int syscall(uint32_t eax, uint32_t ebx, uint32_t ecx, uint32_t edx,
             uint32_t esi, uint32_t edi);
-- 
cgit v1.2.3