summaryrefslogtreecommitdiff
path: root/src/user/app/ethdump/fs.c
diff options
context:
space:
mode:
authordzwdz2022-08-20 15:05:19 +0200
committerdzwdz2022-08-20 15:05:19 +0200
commit7519e57749e176be60b7185d7bbdc298b1744c3c (patch)
treef320249b75a90a016451acab06c09dbcefdbc89a /src/user/app/ethdump/fs.c
parentf22f019aeba00ccb3cc35fe763c3e87bf5690040 (diff)
user/ethdump: UDP support
Diffstat (limited to 'src/user/app/ethdump/fs.c')
-rw-r--r--src/user/app/ethdump/fs.c135
1 files changed, 112 insertions, 23 deletions
diff --git a/src/user/app/ethdump/fs.c b/src/user/app/ethdump/fs.c
index 5078a13..b8c2f7b 100644
--- a/src/user/app/ethdump/fs.c
+++ b/src/user/app/ethdump/fs.c
@@ -1,63 +1,152 @@
#include "proto.h"
#include <camellia/syscalls.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <user/lib/fs/dir.h>
-enum {
+enum handle_type {
H_ROOT,
H_ETHER,
+ H_UDP,
};
+struct strqueue {
+ struct strqueue *next;
+ size_t len;
+ char buf[];
+};
+
+struct handle {
+ enum handle_type type;
+ struct {
+ struct udp_conn *c;
+ struct strqueue *rx, *rxlast;
+ } udp;
+ handle_t reqh;
+};
+
+
+static void udp_listen_callback(struct udp_conn *c, void *arg) {
+ struct handle *h = arg;
+ h->udp.c = c;
+ h->udp.rx = NULL;
+ h->udp.rxlast = NULL;
+ _syscall_fs_respond(h->reqh, h, 0, 0);
+ h->reqh = -1;
+}
+
+static void udp_recv_callback(const void *buf, size_t len, void *arg) {
+ struct handle *h = arg;
+ if (h->reqh >= 0) {
+ _syscall_fs_respond(h->reqh, buf, len, 0);
+ h->reqh = -1;
+ return;
+ }
+ // TODO don't malloc on the network thread, dumbass
+ struct strqueue *sq = malloc(sizeof(*sq) + len);
+ sq->next = NULL;
+ sq->len = len;
+ memcpy(sq->buf, buf, len);
+ if (h->udp.rx) {
+ h->udp.rxlast->next = sq;
+ h->udp.rxlast = sq;
+ } else {
+ h->udp.rx = sq;
+ h->udp.rxlast = sq;
+ }
+}
+
+static void udp_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) {
+ _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;
+ }
+}
+
void fs_thread(void *arg) { (void)arg;
const size_t buflen = 4096;
char *buf = malloc(buflen);
for (;;) {
struct fs_wait_response res;
- handle_t h = _syscall_fs_wait(buf, buflen, &res);
- if (h < 0) break;
+ handle_t reqh = _syscall_fs_wait(buf, buflen, &res);
+ if (reqh < 0) break;
+ struct handle *h = res.id;
+ long ret;
switch (res.op) {
- long ret;
case VFSOP_OPEN:
- ret = -1;
- if (res.len < buflen) {
- buf[res.len] = '\0';
- if (!strcmp("/", buf)) ret = H_ROOT;
- else if (!strcmp("/raw", buf)) ret = H_ETHER;
+ if (res.len == 1 && !memcmp("/", buf, 1)) {
+ h = malloc(sizeof *h);
+ h->type = H_ROOT;
+ _syscall_fs_respond(reqh, h, 0, 0);
+ } else if (res.len == 4 && !memcmp("/raw", buf, 4)) {
+ h = malloc(sizeof *h);
+ h->type = H_ETHER;
+ _syscall_fs_respond(reqh, h, 0, 0);
+ } else if (res.len > 6 && !memcmp("/udpl/", buf, 6)) {
+ uint16_t port = strtol(buf + 6, NULL, 0);
+ h = malloc(sizeof *h);
+ h->type = H_UDP;
+ h->udp.c = NULL;
+ h->reqh = reqh;
+ udp_listen(port, udp_listen_callback, udp_recv_callback, h);
+ } else {
+ _syscall_fs_respond(reqh, NULL, -1, 0);
}
- _syscall_fs_respond(h, (void*)ret, ret, 0);
break;
case VFSOP_READ:
- switch ((long)res.id) {
- struct dirbuild db;
- struct queue_entry *qe;
- case H_ROOT:
+ switch (h->type) {
+ case H_ROOT: {
+ struct dirbuild db;
dir_start(&db, res.offset, buf, sizeof buf);
dir_append(&db, "raw");
- _syscall_fs_respond(h, buf, dir_finish(&db), 0);
- break;
- case H_ETHER:
+ dir_append(&db, "udpl/");
+ _syscall_fs_respond(reqh, buf, dir_finish(&db), 0);
+ break;}
+ case H_ETHER: {
+ struct ethq *qe;
qe = malloc(sizeof *qe);
- qe->h = h;
+ qe->h = reqh;
qe->next = ether_queue;
ether_queue = qe;
+ break;}
+ case H_UDP:
+ udp_recv_enqueue(h, reqh);
break;
default:
- _syscall_fs_respond(h, NULL, -1, 0);
+ _syscall_fs_respond(reqh, NULL, -1, 0);
}
break;
case VFSOP_WRITE:
- switch ((long)res.id) {
+ switch (h->type) {
case H_ETHER:
ret = _syscall_write(state.raw_h, buf, res.len, 0, 0);
- _syscall_fs_respond(h, NULL, ret, 0);
+ _syscall_fs_respond(reqh, NULL, ret, 0);
+ break;
+ case H_UDP:
+ udpc_send(h->udp.c, buf, res.len);
+ _syscall_fs_respond(reqh, NULL, res.len, 0);
break;
default:
- _syscall_fs_respond(h, NULL, -1, 0);
+ _syscall_fs_respond(reqh, NULL, -1, 0);
}
break;
+ 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);
+ free(h);
+ _syscall_fs_respond(reqh, NULL, -1, 0);
+ break;
default:
- _syscall_fs_respond(h, NULL, -1, 0);
+ _syscall_fs_respond(reqh, NULL, -1, 0);
break;
}
}