summaryrefslogtreecommitdiff
path: root/src/user/app
diff options
context:
space:
mode:
Diffstat (limited to 'src/user/app')
-rw-r--r--src/user/app/netstack/fs.c32
-rw-r--r--src/user/app/netstack/proto.h2
-rw-r--r--src/user/app/netstack/tcp.c38
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