From: Tulio A M Mendes Date: Thu, 12 Feb 2026 02:01:31 +0000 (-0300) Subject: feat: socket syscalls (socket/bind/listen/accept/connect/send/recv/sendto/recvfrom) X-Git-Url: https://projects.tadryanom.me/docs/POSIX_ROADMAP.md?a=commitdiff_plain;h=e4261d374bce7a5bd3e913ee25937daad3062fde;p=AdrOS.git feat: socket syscalls (socket/bind/listen/accept/connect/send/recv/sendto/recvfrom) Kernel socket subsystem over lwIP TCP/UDP PCBs with ring-buffer RX, wait queues for blocking ops, and fd integration via sentinel file structs (flags=0x534F434B). Socket dispatch extracted to separate noinline function to prevent syscall_handler stack overflow that caused heap corruption. --- diff --git a/include/errno.h b/include/errno.h index 3e607ce..c0f3cc3 100644 --- a/include/errno.h +++ b/include/errno.h @@ -26,5 +26,13 @@ #define ENAMETOOLONG 36 #define ENOSYS 38 #define ENOTEMPTY 39 +#define EAFNOSUPPORT 47 +#define EADDRINUSE 48 +#define ECONNREFUSED 61 +#define ENOTCONN 57 +#define EOPNOTSUPP 95 +#define EPROTONOSUPPORT 93 +#define ECONNRESET 54 +#define ETIMEDOUT 60 #endif diff --git a/include/socket.h b/include/socket.h new file mode 100644 index 0000000..327f910 --- /dev/null +++ b/include/socket.h @@ -0,0 +1,83 @@ +#ifndef SOCKET_H +#define SOCKET_H + +#include +#include + +/* Address families */ +#define AF_INET 2 + +/* Socket types */ +#define SOCK_STREAM 1 /* TCP */ +#define SOCK_DGRAM 2 /* UDP */ + +/* Protocols */ +#define IPPROTO_TCP 6 +#define IPPROTO_UDP 17 + +/* Shutdown how */ +#define SHUT_RD 0 +#define SHUT_WR 1 +#define SHUT_RDWR 2 + +/* Socket options */ +#define SOL_SOCKET 1 +#define SO_REUSEADDR 2 +#define SO_ERROR 4 +#define SO_KEEPALIVE 9 + +/* sockaddr_in (IPv4) — matches POSIX layout */ +struct sockaddr_in { + uint16_t sin_family; + uint16_t sin_port; /* network byte order */ + uint32_t sin_addr; /* network byte order */ + uint8_t sin_zero[8]; +}; + +/* Generic sockaddr */ +struct sockaddr { + uint16_t sa_family; + char sa_data[14]; +}; + +typedef uint32_t socklen_t; + +/* Max kernel sockets */ +#define KSOCKET_MAX 16 +#define KSOCKET_RX_BUF_SIZE 4096 +#define KSOCKET_ACCEPT_MAX 4 + +/* Kernel socket states */ +#define KSOCK_CLOSED 0 +#define KSOCK_CREATED 1 +#define KSOCK_BOUND 2 +#define KSOCK_LISTENING 3 +#define KSOCK_CONNECTING 4 +#define KSOCK_CONNECTED 5 +#define KSOCK_PEER_CLOSED 6 + +/* Byte order helpers (x86 is little-endian) */ +static inline uint16_t htons(uint16_t x) { return (uint16_t)((x >> 8) | (x << 8)); } +static inline uint16_t ntohs(uint16_t x) { return htons(x); } +static inline uint32_t htonl(uint32_t x) { + return ((x >> 24) & 0xFF) | ((x >> 8) & 0xFF00) | + ((x << 8) & 0xFF0000) | ((x << 24) & 0xFF000000U); +} +static inline uint32_t ntohl(uint32_t x) { return htonl(x); } + +/* Kernel socket API (called from syscall layer) */ +int ksocket_create(int domain, int type, int protocol); +int ksocket_bind(int sid, const struct sockaddr_in* addr); +int ksocket_listen(int sid, int backlog); +int ksocket_accept(int sid, struct sockaddr_in* addr); +int ksocket_connect(int sid, const struct sockaddr_in* addr); +int ksocket_send(int sid, const void* buf, size_t len, int flags); +int ksocket_recv(int sid, void* buf, size_t len, int flags); +int ksocket_sendto(int sid, const void* buf, size_t len, int flags, + const struct sockaddr_in* dest); +int ksocket_recvfrom(int sid, void* buf, size_t len, int flags, + struct sockaddr_in* src); +int ksocket_close(int sid); +void ksocket_init(void); + +#endif diff --git a/include/syscall.h b/include/syscall.h index 2948163..469e387 100644 --- a/include/syscall.h +++ b/include/syscall.h @@ -78,6 +78,16 @@ enum { SYSCALL_READLINK = 56, SYSCALL_SET_THREAD_AREA = 57, + + SYSCALL_SOCKET = 58, + SYSCALL_BIND = 59, + SYSCALL_LISTEN = 60, + SYSCALL_ACCEPT = 61, + SYSCALL_CONNECT = 62, + SYSCALL_SEND = 63, + SYSCALL_RECV = 64, + SYSCALL_SENDTO = 65, + SYSCALL_RECVFROM = 66, }; #endif diff --git a/src/kernel/init.c b/src/kernel/init.c index 7547bdd..97a6c70 100644 --- a/src/kernel/init.c +++ b/src/kernel/init.c @@ -15,6 +15,7 @@ #include "pci.h" #include "e1000.h" #include "net.h" +#include "socket.h" #include "vbe.h" #include "uart_console.h" @@ -73,6 +74,7 @@ int init_start(const struct boot_info* bi) { pci_init(); e1000_init(); net_init(); + ksocket_init(); vbe_init(bi); tty_init(); diff --git a/src/kernel/socket.c b/src/kernel/socket.c new file mode 100644 index 0000000..ec7baf5 --- /dev/null +++ b/src/kernel/socket.c @@ -0,0 +1,435 @@ +#include "socket.h" +#include "net.h" +#include "errno.h" +#include "process.h" +#include "waitqueue.h" +#include "uart_console.h" +#include "utils.h" + +#include "lwip/tcp.h" +#include "lwip/udp.h" +#include "lwip/ip_addr.h" +#include "lwip/pbuf.h" + +#include + +/* ------------------------------------------------------------------ */ +/* Kernel socket table */ +/* ------------------------------------------------------------------ */ + +struct ksocket { + int in_use; + int type; /* SOCK_STREAM or SOCK_DGRAM */ + int state; + union { + struct tcp_pcb* tcp; + struct udp_pcb* udp; + } pcb; + + /* Receive ring buffer */ + uint8_t rx_buf[KSOCKET_RX_BUF_SIZE]; + uint16_t rx_head; + uint16_t rx_tail; + uint16_t rx_count; + + /* Accept queue (TCP listening sockets) */ + int accept_queue[KSOCKET_ACCEPT_MAX]; + int aq_head; + int aq_tail; + int aq_count; + + /* UDP recvfrom: last received source */ + uint32_t last_remote_ip; + uint16_t last_remote_port; + + /* Wait queues */ + waitqueue_t rx_wq; + waitqueue_t accept_wq; + waitqueue_t connect_wq; + + int error; +}; + +static struct ksocket sockets[KSOCKET_MAX]; + +void ksocket_init(void) { + for (int i = 0; i < KSOCKET_MAX; i++) { + sockets[i].in_use = 0; + } +} + +static int alloc_socket(void) { + for (int i = 0; i < KSOCKET_MAX; i++) { + if (!sockets[i].in_use) { + memset(&sockets[i], 0, sizeof(struct ksocket)); + sockets[i].in_use = 1; + sockets[i].state = KSOCK_CREATED; + wq_init(&sockets[i].rx_wq); + wq_init(&sockets[i].accept_wq); + wq_init(&sockets[i].connect_wq); + return i; + } + } + return -ENOMEM; +} + +static struct ksocket* get_socket(int sid) { + if (sid < 0 || sid >= KSOCKET_MAX) return NULL; + if (!sockets[sid].in_use) return NULL; + return &sockets[sid]; +} + +/* ------------------------------------------------------------------ */ +/* Ring buffer helpers */ +/* ------------------------------------------------------------------ */ + +static int rxbuf_write(struct ksocket* s, const void* data, uint16_t len) { + const uint8_t* src = data; + uint16_t avail = KSOCKET_RX_BUF_SIZE - s->rx_count; + if (len > avail) len = avail; + for (uint16_t i = 0; i < len; i++) { + s->rx_buf[s->rx_tail] = src[i]; + s->rx_tail = (uint16_t)((s->rx_tail + 1) % KSOCKET_RX_BUF_SIZE); + s->rx_count++; + } + return len; +} + +static int rxbuf_read(struct ksocket* s, void* data, uint16_t len) { + uint8_t* dst = data; + if (len > s->rx_count) len = s->rx_count; + for (uint16_t i = 0; i < len; i++) { + dst[i] = s->rx_buf[s->rx_head]; + s->rx_head = (uint16_t)((s->rx_head + 1) % KSOCKET_RX_BUF_SIZE); + s->rx_count--; + } + return len; +} + +/* ------------------------------------------------------------------ */ +/* lwIP TCP callbacks */ +/* ------------------------------------------------------------------ */ + +static err_t tcp_recv_cb(void* arg, struct tcp_pcb* tpcb, struct pbuf* p, err_t err) { + int sid = (int)(uintptr_t)arg; + struct ksocket* s = get_socket(sid); + if (!s) { if (p) pbuf_free(p); return ERR_ABRT; } + + if (!p || err != ERR_OK) { + /* Peer closed */ + s->state = KSOCK_PEER_CLOSED; + wq_wake_all(&s->rx_wq); + if (p) pbuf_free(p); + return ERR_OK; + } + + /* Copy data into ring buffer */ + uint16_t copied = 0; + for (struct pbuf* q = p; q != NULL; q = q->next) { + copied += (uint16_t)rxbuf_write(s, q->payload, q->len); + } + tcp_recved(tpcb, copied); + pbuf_free(p); + + wq_wake_all(&s->rx_wq); + return ERR_OK; +} + +static err_t tcp_connected_cb(void* arg, struct tcp_pcb* tpcb, err_t err) { + (void)tpcb; + int sid = (int)(uintptr_t)arg; + struct ksocket* s = get_socket(sid); + if (!s) return ERR_ABRT; + + if (err == ERR_OK) { + s->state = KSOCK_CONNECTED; + } else { + s->error = -ECONNREFUSED; + s->state = KSOCK_CLOSED; + } + wq_wake_all(&s->connect_wq); + return ERR_OK; +} + +static err_t tcp_accept_cb(void* arg, struct tcp_pcb* newpcb, err_t err) { + int sid = (int)(uintptr_t)arg; + struct ksocket* s = get_socket(sid); + if (!s || err != ERR_OK) return ERR_ABRT; + + if (s->aq_count >= KSOCKET_ACCEPT_MAX) { + return ERR_MEM; /* Reject — queue full */ + } + + /* Allocate a new ksocket for the accepted connection */ + int new_sid = alloc_socket(); + if (new_sid < 0) return ERR_MEM; + + struct ksocket* ns = &sockets[new_sid]; + ns->type = SOCK_STREAM; + ns->state = KSOCK_CONNECTED; + ns->pcb.tcp = newpcb; + + tcp_arg(newpcb, (void*)(uintptr_t)new_sid); + tcp_recv(newpcb, tcp_recv_cb); + + /* Enqueue */ + s->accept_queue[s->aq_tail] = new_sid; + s->aq_tail = (s->aq_tail + 1) % KSOCKET_ACCEPT_MAX; + s->aq_count++; + + wq_wake_all(&s->accept_wq); + return ERR_OK; +} + +/* ------------------------------------------------------------------ */ +/* lwIP UDP callback */ +/* ------------------------------------------------------------------ */ + +static void udp_recv_cb(void* arg, struct udp_pcb* upcb, struct pbuf* p, + const ip_addr_t* addr, u16_t port) { + (void)upcb; + int sid = (int)(uintptr_t)arg; + struct ksocket* s = get_socket(sid); + if (!s || !p) { if (p) pbuf_free(p); return; } + + s->last_remote_ip = ip_addr_get_ip4_u32(addr); + s->last_remote_port = port; + + for (struct pbuf* q = p; q != NULL; q = q->next) { + rxbuf_write(s, q->payload, q->len); + } + pbuf_free(p); + + wq_wake_all(&s->rx_wq); +} + +/* ------------------------------------------------------------------ */ +/* Public API */ +/* ------------------------------------------------------------------ */ + +int ksocket_create(int domain, int type, int protocol) { + (void)protocol; + if (domain != AF_INET) return -EAFNOSUPPORT; + if (type != SOCK_STREAM && type != SOCK_DGRAM) return -EPROTONOSUPPORT; + + int sid = alloc_socket(); + if (sid < 0) return sid; + + struct ksocket* s = &sockets[sid]; + s->type = type; + + if (type == SOCK_STREAM) { + s->pcb.tcp = tcp_new(); + if (!s->pcb.tcp) { s->in_use = 0; return -ENOMEM; } + tcp_arg(s->pcb.tcp, (void*)(uintptr_t)sid); + tcp_recv(s->pcb.tcp, tcp_recv_cb); + } else { + s->pcb.udp = udp_new(); + if (!s->pcb.udp) { s->in_use = 0; return -ENOMEM; } + udp_recv(s->pcb.udp, udp_recv_cb, (void*)(uintptr_t)sid); + } + + return sid; +} + +int ksocket_bind(int sid, const struct sockaddr_in* addr) { + struct ksocket* s = get_socket(sid); + if (!s) return -EBADF; + + ip_addr_t ip; + ip_addr_set_ip4_u32(&ip, addr->sin_addr); + uint16_t port = ntohs(addr->sin_port); + + err_t err; + if (s->type == SOCK_STREAM) { + err = tcp_bind(s->pcb.tcp, &ip, port); + } else { + err = udp_bind(s->pcb.udp, &ip, port); + } + + if (err != ERR_OK) return -EADDRINUSE; + s->state = KSOCK_BOUND; + return 0; +} + +int ksocket_listen(int sid, int backlog) { + (void)backlog; + struct ksocket* s = get_socket(sid); + if (!s) return -EBADF; + if (s->type != SOCK_STREAM) return -EOPNOTSUPP; + + struct tcp_pcb* lpcb = tcp_listen(s->pcb.tcp); + if (!lpcb) return -ENOMEM; + + s->pcb.tcp = lpcb; + s->state = KSOCK_LISTENING; + tcp_arg(lpcb, (void*)(uintptr_t)sid); + tcp_accept(lpcb, tcp_accept_cb); + + return 0; +} + +int ksocket_accept(int sid, struct sockaddr_in* addr) { + struct ksocket* s = get_socket(sid); + if (!s) return -EBADF; + if (s->state != KSOCK_LISTENING) return -EINVAL; + + /* Block until a connection arrives */ + while (s->aq_count == 0) { + wq_push(&s->accept_wq, current_process); + current_process->state = PROCESS_BLOCKED; + schedule(); + } + + int new_sid = s->accept_queue[s->aq_head]; + s->aq_head = (s->aq_head + 1) % KSOCKET_ACCEPT_MAX; + s->aq_count--; + + if (addr) { + struct ksocket* ns = get_socket(new_sid); + if (ns && ns->pcb.tcp) { + addr->sin_family = AF_INET; + addr->sin_port = htons(ns->pcb.tcp->remote_port); + addr->sin_addr = ip_addr_get_ip4_u32(&ns->pcb.tcp->remote_ip); + } + } + + return new_sid; +} + +int ksocket_connect(int sid, const struct sockaddr_in* addr) { + struct ksocket* s = get_socket(sid); + if (!s) return -EBADF; + + ip_addr_t ip; + ip_addr_set_ip4_u32(&ip, addr->sin_addr); + uint16_t port = ntohs(addr->sin_port); + + if (s->type == SOCK_STREAM) { + s->state = KSOCK_CONNECTING; + err_t err = tcp_connect(s->pcb.tcp, &ip, port, tcp_connected_cb); + if (err != ERR_OK) return -ECONNREFUSED; + + /* Block until connected */ + while (s->state == KSOCK_CONNECTING) { + wq_push(&s->connect_wq, current_process); + current_process->state = PROCESS_BLOCKED; + schedule(); + } + if (s->state != KSOCK_CONNECTED) return s->error ? s->error : -ECONNREFUSED; + return 0; + } else { + /* UDP "connect" just sets the default destination */ + udp_connect(s->pcb.udp, &ip, port); + s->state = KSOCK_CONNECTED; + return 0; + } +} + +int ksocket_send(int sid, const void* buf, size_t len, int flags) { + (void)flags; + struct ksocket* s = get_socket(sid); + if (!s) return -EBADF; + + if (s->type == SOCK_STREAM) { + if (s->state != KSOCK_CONNECTED) return -ENOTCONN; + uint16_t snd_len = (len > 0xFFFF) ? 0xFFFF : (uint16_t)len; + uint16_t avail = tcp_sndbuf(s->pcb.tcp); + if (snd_len > avail) snd_len = avail; + if (snd_len == 0) return -EAGAIN; + + err_t err = tcp_write(s->pcb.tcp, buf, snd_len, TCP_WRITE_FLAG_COPY); + if (err != ERR_OK) return -EIO; + tcp_output(s->pcb.tcp); + return (int)snd_len; + } else { + /* UDP connected send */ + if (s->state != KSOCK_CONNECTED) return -ENOTCONN; + struct pbuf* p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)len, PBUF_RAM); + if (!p) return -ENOMEM; + memcpy(p->payload, buf, len); + err_t err = udp_send(s->pcb.udp, p); + pbuf_free(p); + return (err == ERR_OK) ? (int)len : -EIO; + } +} + +int ksocket_recv(int sid, void* buf, size_t len, int flags) { + (void)flags; + struct ksocket* s = get_socket(sid); + if (!s) return -EBADF; + + /* Block until data available or peer closed */ + while (s->rx_count == 0 && s->state != KSOCK_PEER_CLOSED && s->state != KSOCK_CLOSED) { + wq_push(&s->rx_wq, current_process); + current_process->state = PROCESS_BLOCKED; + schedule(); + } + + if (s->rx_count == 0) return 0; /* EOF / peer closed */ + + uint16_t rlen = (len > 0xFFFF) ? 0xFFFF : (uint16_t)len; + return rxbuf_read(s, buf, rlen); +} + +int ksocket_sendto(int sid, const void* buf, size_t len, int flags, + const struct sockaddr_in* dest) { + (void)flags; + struct ksocket* s = get_socket(sid); + if (!s) return -EBADF; + if (s->type != SOCK_DGRAM) return -EOPNOTSUPP; + + ip_addr_t ip; + ip_addr_set_ip4_u32(&ip, dest->sin_addr); + uint16_t port = ntohs(dest->sin_port); + + struct pbuf* p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)len, PBUF_RAM); + if (!p) return -ENOMEM; + memcpy(p->payload, buf, len); + err_t err = udp_sendto(s->pcb.udp, p, &ip, port); + pbuf_free(p); + return (err == ERR_OK) ? (int)len : -EIO; +} + +int ksocket_recvfrom(int sid, void* buf, size_t len, int flags, + struct sockaddr_in* src) { + int ret = ksocket_recv(sid, buf, len, flags); + if (ret > 0 && src) { + struct ksocket* s = get_socket(sid); + if (s) { + src->sin_family = AF_INET; + src->sin_port = htons(s->last_remote_port); + src->sin_addr = s->last_remote_ip; + } + } + return ret; +} + +int ksocket_close(int sid) { + struct ksocket* s = get_socket(sid); + if (!s) return -EBADF; + + if (s->type == SOCK_STREAM && s->pcb.tcp) { + tcp_arg(s->pcb.tcp, NULL); + tcp_recv(s->pcb.tcp, NULL); + tcp_accept(s->pcb.tcp, NULL); + tcp_close(s->pcb.tcp); + } else if (s->type == SOCK_DGRAM && s->pcb.udp) { + udp_remove(s->pcb.udp); + } + + /* Free any pending accepted sockets */ + while (s->aq_count > 0) { + int child = s->accept_queue[s->aq_head]; + s->aq_head = (s->aq_head + 1) % KSOCKET_ACCEPT_MAX; + s->aq_count--; + ksocket_close(child); + } + + wq_wake_all(&s->rx_wq); + wq_wake_all(&s->accept_wq); + wq_wake_all(&s->connect_wq); + + s->in_use = 0; + return 0; +} diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 999115e..68644a1 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -15,6 +15,7 @@ #include "errno.h" #include "shm.h" +#include "socket.h" #if defined(__i386__) extern void x86_sysenter_init(void); @@ -64,6 +65,7 @@ struct sigframe { static int fd_alloc(struct file* f); static int fd_close(int fd); static struct file* fd_get(int fd); +static void socket_syscall_dispatch(struct registers* regs, uint32_t syscall_no); struct pollfd { int fd; @@ -582,7 +584,9 @@ static int fd_close(int fd) { current_process->files[fd] = NULL; if (__sync_sub_and_fetch(&f->refcount, 1) == 0) { - if (f->node) { + if (f->flags == 0x534F434BU && f->node == NULL) { + ksocket_close((int)f->offset); + } else if (f->node) { vfs_close(f->node); } kfree(f); @@ -2154,6 +2158,180 @@ void syscall_handler(struct registers* regs) { return; } + /* ---- Socket syscalls ---- */ + socket_syscall_dispatch(regs, syscall_no); + /* If socket dispatch handled it, eax is set and we return. + If not, it sets ENOSYS. Either way, return. */ + return; +} + +/* Separate function to keep socket locals off syscall_handler's stack frame */ +__attribute__((noinline)) +static void socket_syscall_dispatch(struct registers* regs, uint32_t syscall_no) { + if (syscall_no == SYSCALL_SOCKET) { + int domain = (int)regs->ebx; + int type = (int)regs->ecx; + int protocol = (int)regs->edx; + int sid = ksocket_create(domain, type, protocol); + if (sid < 0) { regs->eax = (uint32_t)sid; return; } + int fd = -1; + for (int i = 0; i < PROCESS_MAX_FILES; i++) { + if (!current_process->files[i]) { fd = i; break; } + } + if (fd < 0) { ksocket_close(sid); regs->eax = (uint32_t)-EMFILE; return; } + struct file* f = (struct file*)kmalloc(sizeof(struct file)); + if (!f) { ksocket_close(sid); regs->eax = (uint32_t)-ENOMEM; return; } + f->node = NULL; + f->offset = (uint32_t)sid; + f->flags = 0x534F434BU; /* magic 'SOCK' */ + f->refcount = 1; + current_process->files[fd] = f; + regs->eax = (uint32_t)fd; + return; + } + + if (syscall_no == SYSCALL_BIND) { + int fd = (int)regs->ebx; + if (fd < 0 || fd >= PROCESS_MAX_FILES || !current_process->files[fd] || + current_process->files[fd]->flags != 0x534F434BU) { + regs->eax = (uint32_t)-EBADF; return; + } + struct sockaddr_in sa; + if (copy_from_user(&sa, (const void*)regs->ecx, sizeof(sa)) < 0) { + regs->eax = (uint32_t)-EFAULT; return; + } + int sid = (int)current_process->files[fd]->offset; + regs->eax = (uint32_t)ksocket_bind(sid, &sa); + return; + } + + if (syscall_no == SYSCALL_LISTEN) { + int fd = (int)regs->ebx; + if (fd < 0 || fd >= PROCESS_MAX_FILES || !current_process->files[fd] || + current_process->files[fd]->flags != 0x534F434BU) { + regs->eax = (uint32_t)-EBADF; return; + } + int sid = (int)current_process->files[fd]->offset; + regs->eax = (uint32_t)ksocket_listen(sid, (int)regs->ecx); + return; + } + + if (syscall_no == SYSCALL_ACCEPT) { + int fd = (int)regs->ebx; + if (fd < 0 || fd >= PROCESS_MAX_FILES || !current_process->files[fd] || + current_process->files[fd]->flags != 0x534F434BU) { + regs->eax = (uint32_t)-EBADF; return; + } + int sid = (int)current_process->files[fd]->offset; + struct sockaddr_in sa; + memset(&sa, 0, sizeof(sa)); + int new_sid = ksocket_accept(sid, &sa); + if (new_sid < 0) { regs->eax = (uint32_t)new_sid; return; } + int new_fd = -1; + for (int i = 0; i < PROCESS_MAX_FILES; i++) { + if (!current_process->files[i]) { new_fd = i; break; } + } + if (new_fd < 0) { ksocket_close(new_sid); regs->eax = (uint32_t)-EMFILE; return; } + struct file* f = (struct file*)kmalloc(sizeof(struct file)); + if (!f) { ksocket_close(new_sid); regs->eax = (uint32_t)-ENOMEM; return; } + f->node = NULL; + f->offset = (uint32_t)new_sid; + f->flags = 0x534F434BU; + f->refcount = 1; + current_process->files[new_fd] = f; + if (regs->ecx) { + (void)copy_to_user((void*)regs->ecx, &sa, sizeof(sa)); + } + regs->eax = (uint32_t)new_fd; + return; + } + + if (syscall_no == SYSCALL_CONNECT) { + int fd = (int)regs->ebx; + if (fd < 0 || fd >= PROCESS_MAX_FILES || !current_process->files[fd] || + current_process->files[fd]->flags != 0x534F434BU) { + regs->eax = (uint32_t)-EBADF; return; + } + struct sockaddr_in sa; + if (copy_from_user(&sa, (const void*)regs->ecx, sizeof(sa)) < 0) { + regs->eax = (uint32_t)-EFAULT; return; + } + int sid = (int)current_process->files[fd]->offset; + regs->eax = (uint32_t)ksocket_connect(sid, &sa); + return; + } + + if (syscall_no == SYSCALL_SEND) { + int fd = (int)regs->ebx; + if (fd < 0 || fd >= PROCESS_MAX_FILES || !current_process->files[fd] || + current_process->files[fd]->flags != 0x534F434BU) { + regs->eax = (uint32_t)-EBADF; return; + } + size_t len = (size_t)regs->edx; + if (!user_range_ok((const void*)regs->ecx, len)) { + regs->eax = (uint32_t)-EFAULT; return; + } + int sid = (int)current_process->files[fd]->offset; + regs->eax = (uint32_t)ksocket_send(sid, (const void*)regs->ecx, len, (int)regs->esi); + return; + } + + if (syscall_no == SYSCALL_RECV) { + int fd = (int)regs->ebx; + if (fd < 0 || fd >= PROCESS_MAX_FILES || !current_process->files[fd] || + current_process->files[fd]->flags != 0x534F434BU) { + regs->eax = (uint32_t)-EBADF; return; + } + size_t len = (size_t)regs->edx; + if (!user_range_ok((void*)regs->ecx, len)) { + regs->eax = (uint32_t)-EFAULT; return; + } + int sid = (int)current_process->files[fd]->offset; + regs->eax = (uint32_t)ksocket_recv(sid, (void*)regs->ecx, len, (int)regs->esi); + return; + } + + if (syscall_no == SYSCALL_SENDTO) { + int fd = (int)regs->ebx; + if (fd < 0 || fd >= PROCESS_MAX_FILES || !current_process->files[fd] || + current_process->files[fd]->flags != 0x534F434BU) { + regs->eax = (uint32_t)-EBADF; return; + } + size_t len = (size_t)regs->edx; + if (!user_range_ok((const void*)regs->ecx, len)) { + regs->eax = (uint32_t)-EFAULT; return; + } + struct sockaddr_in dest; + if (copy_from_user(&dest, (const void*)regs->edi, sizeof(dest)) < 0) { + regs->eax = (uint32_t)-EFAULT; return; + } + int sid = (int)current_process->files[fd]->offset; + regs->eax = (uint32_t)ksocket_sendto(sid, (const void*)regs->ecx, len, + (int)regs->esi, &dest); + return; + } + + if (syscall_no == SYSCALL_RECVFROM) { + int fd = (int)regs->ebx; + if (fd < 0 || fd >= PROCESS_MAX_FILES || !current_process->files[fd] || + current_process->files[fd]->flags != 0x534F434BU) { + regs->eax = (uint32_t)-EBADF; return; + } + size_t len = (size_t)regs->edx; + if (!user_range_ok((void*)regs->ecx, len)) { + regs->eax = (uint32_t)-EFAULT; return; + } + struct sockaddr_in src; + memset(&src, 0, sizeof(src)); + int sid = (int)current_process->files[fd]->offset; + int ret = ksocket_recvfrom(sid, (void*)regs->ecx, len, (int)regs->esi, &src); + if (ret > 0 && regs->edi) { + (void)copy_to_user((void*)regs->edi, &src, sizeof(src)); + } + regs->eax = (uint32_t)ret; + return; + } + regs->eax = (uint32_t)-ENOSYS; }