diff options
author | dzwdz | 2022-08-23 20:17:03 +0200 |
---|---|---|
committer | dzwdz | 2022-08-23 20:17:03 +0200 |
commit | 975e592f85f05e98ef2b833e560e2c243b8491ec (patch) | |
tree | 7520b5f29dda12d480d1676a75831c30e19049b1 /src/user | |
parent | 38cf66edaacc4e58b561bea8a77abfd3facf59fe (diff) |
user/netstack: TCP recv
Diffstat (limited to 'src/user')
-rw-r--r-- | src/user/app/netstack/fs.c | 32 | ||||
-rw-r--r-- | src/user/app/netstack/proto.h | 2 | ||||
-rw-r--r-- | src/user/app/netstack/tcp.c | 38 |
3 files changed, 59 insertions, 13 deletions
diff --git a/src/user/app/netstack/fs.c b/src/user/app/netstack/fs.c index cc4491d..cdceada 100644 --- a/src/user/app/netstack/fs.c +++ b/src/user/app/netstack/fs.c @@ -39,6 +39,7 @@ struct handle { } udp; struct { struct tcp_conn *c; + size_t readcap; } tcp; bool dead; handle_t reqh; @@ -52,6 +53,19 @@ static void tcp_listen_callback(struct tcp_conn *c, void *arg) { h->reqh = -1; } +/* also called from recv_enqueue. yes, it's a mess */ +static void tcp_recv_callback(void *arg) { + struct handle *h = arg; + char buf[1024]; + if (h->reqh >= 0) { + size_t len = tcpc_tryread(h->tcp.c, buf, sizeof buf); + if (len > 0) { + _syscall_fs_respond(h->reqh, buf, len, 0); + h->reqh = -1; + } + } +} + static void tcp_close_callback(void *arg) { struct handle *h = arg; h->dead = true; @@ -89,16 +103,22 @@ static void udp_recv_callback(const void *buf, size_t len, void *arg) { } } -static void recv_enqueue(struct handle *h, handle_t reqh) { +static void recv_enqueue(struct handle *h, handle_t reqh, size_t readcap) { if (h->reqh > 0) { // TODO queue _syscall_fs_respond(reqh, NULL, -1, 0); - } else if (h->type == H_UDP && h->udp.rx) { + return; + } + if (h->type == H_UDP && h->udp.rx) { _syscall_fs_respond(reqh, h->udp.rx->buf, h->udp.rx->len, 0); h->udp.rx = h->udp.rx->next; free(h->udp.rx); - } else { - h->reqh = reqh; + return; + } + h->reqh = reqh; + if (h->type == H_TCP) { + h->tcp.readcap = readcap; + tcp_recv_callback(h); } } @@ -156,7 +176,7 @@ static void fs_open(handle_t reqh, char *path) { memset(h, 0, sizeof *h); h->type = H_TCP; h->reqh = reqh; - tcp_listen(port, tcp_listen_callback, tcp_close_callback, h); + tcp_listen(port, tcp_listen_callback, tcp_recv_callback, tcp_close_callback, h); return; } } @@ -222,7 +242,7 @@ void fs_thread(void *arg) { (void)arg; break;} case H_TCP: case H_UDP: - recv_enqueue(h, reqh); + recv_enqueue(h, reqh, res.capacity); break; case H_ARP: arp_fsread(reqh, res.offset); diff --git a/src/user/app/netstack/proto.h b/src/user/app/netstack/proto.h index 0c4338b..eed5361 100644 --- a/src/user/app/netstack/proto.h +++ b/src/user/app/netstack/proto.h @@ -92,6 +92,8 @@ void tcp_parse(const uint8_t *buf, size_t len, struct ipv4 ip); void tcp_listen( uint16_t port, void (*on_conn)(struct tcp_conn *, void *carg), + void (*on_recv)(void *carg), void (*on_close)(void *carg), void *carg); +size_t tcpc_tryread(struct tcp_conn *, void *buf, size_t len); void tcpc_close(struct tcp_conn *); diff --git a/src/user/app/netstack/tcp.c b/src/user/app/netstack/tcp.c index 71e82f2..7f54575 100644 --- a/src/user/app/netstack/tcp.c +++ b/src/user/app/netstack/tcp.c @@ -1,6 +1,10 @@ -/* Welcome to spaghetti land. */ +/* Welcome to spaghetti land. + * This is anything but production quality. It's throwaway code, meant + * only to see how networking could fit into the architecture of the + * system. */ #include "proto.h" #include "util.h" +#include <shared/container/ring.h> enum { SrcPort = 0, @@ -43,8 +47,11 @@ struct tcp_conn { bool uclosed; /* did the user close? */ void (*on_conn)(struct tcp_conn *, void *carg); + void (*on_recv)(void *carg); void (*on_close)(void *carg); void *carg; + + ring_t rx; }; static struct tcp_conn *conns; static void conns_append(struct tcp_conn *c) { @@ -64,7 +71,7 @@ static void tcpc_send(struct tcp_conn *c, uint16_t flags) { nput32(pkt + AckNum, c->lack); flags |= (MinHdr / 4) << 12; nput16(pkt + Flags, flags); - nput16(pkt + WinSize, 4096); + nput16(pkt + WinSize, ring_avail(&c->rx)); nput16(pkt + Checksum, ip_checksumphdr(pkt, MinHdr, c->lip, c->rip, 6)); ipv4_send(pkt, MinHdr, (struct ipv4){ @@ -78,6 +85,7 @@ static void tcpc_send(struct tcp_conn *c, uint16_t flags) { void tcp_listen( uint16_t port, void (*on_conn)(struct tcp_conn *, void *carg), + void (*on_recv)(void *carg), void (*on_close)(void *carg), void *carg) { @@ -86,18 +94,27 @@ void tcp_listen( c->lip = state.ip; c->state = LISTEN; c->on_conn = on_conn; + c->on_recv = on_recv; c->on_close = on_close; c->carg = carg; + // TODO setting the ring size super low loses every nth byte. probably a bug with ring_t itself! + c->rx = (ring_t){malloc(4096), 4096, 0, 0}; conns_append(c); } +size_t tcpc_tryread(struct tcp_conn *c, void *buf, size_t len) { + if (!buf) return ring_used(&c->rx); + return ring_get(&c->rx, buf, len); +} void tcpc_close(struct tcp_conn *c) { /* ONLY FOR USE BY THE USER, drops their reference */ if (!c->uclosed) { c->uclosed = true; - tcpc_send(c, FlagFIN | FlagACK); - c->state = LAST_ACK; - c->on_conn = NULL; - c->on_close = NULL; + if (c->state != CLOSED && c->state != LAST_ACK && c->state != LISTEN) { + tcpc_send(c, FlagFIN | FlagACK); + c->state = LAST_ACK; + c->on_conn = NULL; + c->on_close = NULL; + } } } @@ -146,7 +163,14 @@ void tcp_parse(const uint8_t *buf, size_t len, struct ipv4 ip) { tcpc_send(iter, FlagACK); return; } - iter->lack = seq + 1; + // TODO min() in libc + // TODO check if overflows window size + iter->lack = seq + (payloadlen < 1 ? 1 : payloadlen); + if (payloadlen) { + ring_put(&iter->rx, buf + hdrlen, payloadlen); + if (iter->on_recv) iter->on_recv(iter->carg); + tcpc_send(iter, FlagACK); + } if (flags & FlagFIN) { // TODO should resend the packet until an ACK is received // TODO duplicated in tcpc_close |