diff options
author | dzwdz | 2022-08-20 15:05:19 +0200 |
---|---|---|
committer | dzwdz | 2022-08-20 15:05:19 +0200 |
commit | 7519e57749e176be60b7185d7bbdc298b1744c3c (patch) | |
tree | f320249b75a90a016451acab06c09dbcefdbc89a /src/user/app/ethdump/fs.c | |
parent | f22f019aeba00ccb3cc35fe763c3e87bf5690040 (diff) |
user/ethdump: UDP support
Diffstat (limited to 'src/user/app/ethdump/fs.c')
-rw-r--r-- | src/user/app/ethdump/fs.c | 135 |
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; } } |