summaryrefslogtreecommitdiff
path: root/src/user/app/netstack/fs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/user/app/netstack/fs.c')
-rw-r--r--src/user/app/netstack/fs.c59
1 files changed, 52 insertions, 7 deletions
diff --git a/src/user/app/netstack/fs.c b/src/user/app/netstack/fs.c
index 19e5bfd..cc4491d 100644
--- a/src/user/app/netstack/fs.c
+++ b/src/user/app/netstack/fs.c
@@ -6,19 +6,21 @@
* ARP cache (currently read-only)
* /net/0.0.0.0/connect/1.2.3.4/udp/53
* connect from 0.0.0.0 (any ip) to 1.2.3.4 on udp port 53
- * /net/0.0.0.0/listen/udp/53
+ * /net/0.0.0.0/listen/{tcp,udp}/53
* waits for a connection to any ip on udp port 53
* open() returns once a connection to ip 0.0.0.0 on udp port 53 is received
*/
#include "proto.h"
#include "util.h"
#include <camellia/syscalls.h>
+#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum handle_type {
H_ETHER,
+ H_TCP,
H_UDP,
H_ARP,
};
@@ -35,10 +37,31 @@ struct handle {
struct udp_conn *c;
struct strqueue *rx, *rxlast;
} udp;
+ struct {
+ struct tcp_conn *c;
+ } tcp;
+ bool dead;
handle_t reqh;
};
+static void tcp_listen_callback(struct tcp_conn *c, void *arg) {
+ struct handle *h = arg;
+ h->tcp.c = c;
+ _syscall_fs_respond(h->reqh, h, 0, 0);
+ h->reqh = -1;
+}
+
+static void tcp_close_callback(void *arg) {
+ struct handle *h = arg;
+ h->dead = true;
+ if (h->reqh >= 0) {
+ _syscall_fs_respond(h->reqh, NULL, -ECONNRESET, 0);
+ h->reqh = -1;
+ return;
+ }
+}
+
static void udp_listen_callback(struct udp_conn *c, void *arg) {
struct handle *h = arg;
h->udp.c = c;
@@ -66,11 +89,11 @@ static void udp_recv_callback(const void *buf, size_t len, void *arg) {
}
}
-static void udp_recv_enqueue(struct handle *h, handle_t reqh) {
+static void recv_enqueue(struct handle *h, handle_t reqh) {
if (h->reqh > 0) {
// TODO queue
_syscall_fs_respond(reqh, NULL, -1, 0);
- } else if (h->udp.rx) {
+ } else 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);
@@ -87,10 +110,12 @@ static void fs_open(handle_t reqh, char *path) {
if (strcmp(path, "raw") == 0) {
h = malloc(sizeof *h);
+ memset(h, 0, sizeof *h);
h->type = H_ETHER;
respond(h, 0);
} else if (strcmp(path, "arp") == 0) {
h = malloc(sizeof *h);
+ memset(h, 0, sizeof *h);
h->type = H_ARP;
respond(h, 0);
}
@@ -118,12 +143,23 @@ static void fs_open(handle_t reqh, char *path) {
h = malloc(sizeof *h);
memset(h, 0, sizeof *h);
h->type = H_UDP;
- h->udp.c = NULL;
h->reqh = reqh;
udp_listen(port, udp_listen_callback, udp_recv_callback, h);
return;
}
}
+ if (strcmp(proto, "tcp") == 0) {
+ port_s = strtok_r(NULL, "/", &save);
+ if (port_s) {
+ uint16_t port = strtol(port_s, NULL, 0);
+ h = malloc(sizeof *h);
+ memset(h, 0, sizeof *h);
+ h->type = H_TCP;
+ h->reqh = reqh;
+ tcp_listen(port, tcp_listen_callback, tcp_close_callback, h);
+ return;
+ }
+ }
} else if (strcmp(verb, "connect") == 0) {
if (ip_parse(strtok_r(NULL, "/", &save), &dstip) < 0)
respond(NULL, -1);
@@ -172,6 +208,10 @@ void fs_thread(void *arg) { (void)arg;
}
break;
case VFSOP_READ:
+ if (h->dead) {
+ _syscall_fs_respond(reqh, NULL, -ECONNRESET, 0);
+ break;
+ }
switch (h->type) {
case H_ETHER: {
struct ethq *qe;
@@ -180,8 +220,9 @@ void fs_thread(void *arg) { (void)arg;
qe->next = ether_queue;
ether_queue = qe;
break;}
+ case H_TCP:
case H_UDP:
- udp_recv_enqueue(h, reqh);
+ recv_enqueue(h, reqh);
break;
case H_ARP:
arp_fsread(reqh, res.offset);
@@ -191,6 +232,10 @@ void fs_thread(void *arg) { (void)arg;
}
break;
case VFSOP_WRITE:
+ if (h->dead) {
+ _syscall_fs_respond(reqh, NULL, -ECONNRESET, 0);
+ break;
+ }
switch (h->type) {
case H_ETHER:
ret = _syscall_write(state.raw_h, buf, res.len, 0, 0);
@@ -207,8 +252,8 @@ void fs_thread(void *arg) { (void)arg;
case VFSOP_CLOSE:
// TODO remove entries in queue
// TODO why does close even have _syscall_fs_respond?
- if (h->type == H_UDP)
- udpc_close(h->udp.c);
+ if (h->type == H_TCP) tcpc_close(h->tcp.c);
+ if (h->type == H_UDP) udpc_close(h->udp.c);
free(h);
_syscall_fs_respond(reqh, NULL, -1, 0);
break;