123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487 |
- /* vim: tabstop=4 shiftwidth=4 noexpandtab
- * This file is part of ToaruOS and is released under the terms
- * of the NCSA / University of Illinois License - see LICENSE.md
- * Copyright (C) 2014-2018 K. Lange
- */
- #include <kernel/system.h>
- #include <kernel/fs.h>
- #include <kernel/pipe.h>
- #include <kernel/module.h>
- #include <kernel/logging.h>
- #include <sys/ioctl.h>
- #define MAX_PACKET_SIZE 1024
- typedef struct packet_manager {
- /* uh, nothing, lol */
- list_t * exchanges;
- spin_lock_t lock;
- } pex_t;
- typedef struct packet_exchange {
- char * name;
- char fresh;
- spin_lock_t lock;
- fs_node_t * server_pipe;
- list_t * clients;
- } pex_ex_t;
- typedef struct packet_client {
- pex_ex_t * parent;
- fs_node_t * pipe;
- } pex_client_t;
- typedef struct packet {
- pex_client_t * source;
- size_t size;
- uint8_t data[];
- } packet_t;
- typedef struct server_write_header {
- pex_client_t * target;
- uint8_t data[];
- } header_t;
- static void receive_packet(fs_node_t * socket, packet_t ** out) {
- packet_t tmp;
- read_fs(socket, 0, sizeof(struct packet), (uint8_t *)&tmp);
- *out = malloc(tmp.size + sizeof(struct packet));
- memcpy(*out, &tmp, sizeof(struct packet));
- if (tmp.size) {
- read_fs(socket, 0, tmp.size, (uint8_t *)(*out)->data);
- }
- }
- static void send_to_server(pex_ex_t * p, pex_client_t * c, size_t size, void * data) {
- size_t p_size = size + sizeof(struct packet);
- packet_t * packet = malloc(p_size);
- packet->source = c;
- packet->size = size;
- if (size) {
- memcpy(packet->data, data, size);
- }
- write_fs(p->server_pipe, 0, p_size, (uint8_t *)packet);
- free(packet);
- }
- static int send_to_client(pex_ex_t * p, pex_client_t * c, size_t size, void * data) {
- size_t p_size = size + sizeof(struct packet);
- /* Verify there is space on the client */
- if (pipe_unsize(c->pipe) < (int)p_size) {
- return -1;
- }
- packet_t * packet = malloc(p_size);
- memcpy(packet->data, data, size);
- packet->source = NULL;
- packet->size = size;
- write_fs(c->pipe, 0, p_size, (uint8_t *)packet);
- free(packet);
- return size;
- }
- static pex_client_t * create_client(pex_ex_t * p) {
- pex_client_t * out = malloc(sizeof(pex_client_t));
- out->parent = p;
- out->pipe = make_pipe(4096);
- return out;
- }
- static uint32_t read_server(fs_node_t * node, uint64_t offset, uint32_t size, uint8_t * buffer) {
- pex_ex_t * p = (pex_ex_t *)node->device;
- debug_print(INFO, "[pex] server read(...)");
- packet_t * packet;
- receive_packet(p->server_pipe, &packet);
- debug_print(INFO, "Server recevied packet of size %d, was waiting for at most %d", packet->size, size);
- if (packet->size + sizeof(packet_t) > size) {
- return -1;
- }
- memcpy(buffer, packet, packet->size + sizeof(packet_t));
- uint32_t out = packet->size + sizeof(packet_t);
- free(packet);
- return out;
- }
- static uint32_t write_server(fs_node_t * node, uint64_t offset, uint32_t size, uint8_t * buffer) {
- pex_ex_t * p = (pex_ex_t *)node->device;
- debug_print(INFO, "[pex] server write(...)");
- header_t * head = (header_t *)buffer;
- if (size - sizeof(header_t) > MAX_PACKET_SIZE) {
- return -1;
- }
- if (head->target == NULL) {
- /* Brodcast packet */
- spin_lock(p->lock);
- foreach(f, p->clients) {
- debug_print(INFO, "Sending to client 0x%x", f->value);
- send_to_client(p, (pex_client_t *)f->value, size - sizeof(header_t), head->data);
- }
- spin_unlock(p->lock);
- debug_print(INFO, "Done broadcasting to clients.");
- return size;
- } else if (head->target->parent != p) {
- debug_print(WARNING, "[pex] Invalid packet from server? (pid=%d)", current_process->id);
- return -1;
- }
- return send_to_client(p, head->target, size - sizeof(header_t), head->data);
- }
- static int ioctl_server(fs_node_t * node, int request, void * argp) {
- pex_ex_t * p = (pex_ex_t *)node->device;
- switch (request) {
- case IOCTL_PACKETFS_QUEUED:
- return pipe_size(p->server_pipe);
- default:
- return -1;
- }
- }
- static uint32_t read_client(fs_node_t * node, uint64_t offset, uint32_t size, uint8_t * buffer) {
- pex_client_t * c = (pex_client_t *)node->inode;
- if (c->parent != node->device) {
- debug_print(WARNING, "[pex] Invalid device endpoint on client read?");
- return -1;
- }
- debug_print(INFO, "[pex] client read(...)");
- packet_t * packet;
- receive_packet(c->pipe, &packet);
- if (packet->size > size) {
- debug_print(WARNING, "[pex] Client is not reading enough bytes to hold packet of size %d", packet->size);
- return -1;
- }
- memcpy(buffer, &packet->data, packet->size);
- uint32_t out = packet->size;
- debug_print(INFO, "[pex] Client received packet of size %d", packet->size);
- free(packet);
- return out;
- }
- static uint32_t write_client(fs_node_t * node, uint64_t offset, uint32_t size, uint8_t * buffer) {
- pex_client_t * c = (pex_client_t *)node->inode;
- if (c->parent != node->device) {
- debug_print(WARNING, "[pex] Invalid device endpoint on client write?");
- return -1;
- }
- debug_print(INFO, "[pex] client write(...)");
- if (size > MAX_PACKET_SIZE) {
- debug_print(WARNING, "Size of %d is too big.", size);
- return -1;
- }
- debug_print(INFO, "Sending packet of size %d to parent", size);
- send_to_server(c->parent, c, size, buffer);
- return size;
- }
- static int ioctl_client(fs_node_t * node, int request, void * argp) {
- pex_client_t * c = (pex_client_t *)node->inode;
- switch (request) {
- case IOCTL_PACKETFS_QUEUED:
- return pipe_size(c->pipe);
- default:
- return -1;
- }
- }
- static void close_client(fs_node_t * node) {
- pex_client_t * c = (pex_client_t *)node->inode;
- pex_ex_t * p = c->parent;
- debug_print(WARNING, "Closing packetfs client: 0x%x:0x%x", p, c);
- spin_lock(p->lock);
- node_t * n = list_find(p->clients, c);
- if (n && n->owner == p->clients) {
- list_delete(p->clients, n);
- free(n);
- }
- spin_unlock(p->lock);
- char tmp[1];
- send_to_server(p, c, 0, tmp);
- free(c);
- }
- static int wait_server(fs_node_t * node, void * process) {
- pex_ex_t * p = (pex_ex_t *)node->device;
- return selectwait_fs(p->server_pipe, process);
- }
- static int check_server(fs_node_t * node) {
- pex_ex_t * p = (pex_ex_t *)node->device;
- return selectcheck_fs(p->server_pipe);
- }
- static int wait_client(fs_node_t * node, void * process) {
- pex_client_t * c = (pex_client_t *)node->inode;
- return selectwait_fs(c->pipe, process);
- }
- static int check_client(fs_node_t * node) {
- pex_client_t * c = (pex_client_t *)node->inode;
- return selectcheck_fs(c->pipe);
- }
- static void open_pex(fs_node_t * node, unsigned int flags) {
- pex_ex_t * t = (pex_ex_t *)(node->device);
- debug_print(NOTICE, "Opening packet exchange %s with flags 0x%x", t->name, flags);
- if (flags & O_CREAT && t->fresh) {
- t->fresh = 0;
- node->inode = 0;
- /* Set up the server side */
- node->read = read_server;
- node->write = write_server;
- node->ioctl = ioctl_server;
- node->selectcheck = check_server;
- node->selectwait = wait_server;
- debug_print(INFO, "[pex] Server launched: %s", t->name);
- debug_print(INFO, "fs_node = 0x%x", node);
- } else if (!(flags & O_CREAT)) {
- pex_client_t * client = create_client(t);
- node->inode = (uintptr_t)client;
- node->read = read_client;
- node->write = write_client;
- node->ioctl = ioctl_client;
- node->close = close_client;
- node->selectcheck = check_client;
- node->selectwait = wait_client;
- list_insert(t->clients, client);
- /* XXX: Send plumbing message to server for new client connection */
- debug_print(INFO, "[pex] Client connected: %s:0%x", t->name, node->inode);
- } else if (flags & O_CREAT && !t->fresh) {
- /* XXX: You dun goofed */
- }
- return;
- }
- static struct dirent * readdir_packetfs(fs_node_t *node, uint32_t index) {
- pex_t * p = (pex_t *)node->device;
- unsigned int i = 0;
- debug_print(INFO, "[pex] readdir(%d)", index);
- if (index == 0) {
- struct dirent * out = malloc(sizeof(struct dirent));
- memset(out, 0x00, sizeof(struct dirent));
- out->ino = 0;
- strcpy(out->name, ".");
- return out;
- }
- if (index == 1) {
- struct dirent * out = malloc(sizeof(struct dirent));
- memset(out, 0x00, sizeof(struct dirent));
- out->ino = 0;
- strcpy(out->name, "..");
- return out;
- }
- index -= 2;
- if (index >= p->exchanges->length) {
- return NULL;
- }
- spin_lock(p->lock);
- foreach(f, p->exchanges) {
- if (i == index) {
- spin_unlock(p->lock);
- pex_ex_t * t = (pex_ex_t *)f->value;
- struct dirent * out = malloc(sizeof(struct dirent));
- memset(out, 0x00, sizeof(struct dirent));
- out->ino = (uint32_t)t;
- strcpy(out->name, t->name);
- return out;
- } else {
- ++i;
- }
- }
- spin_unlock(p->lock);
- return NULL;
- }
- static fs_node_t * file_from_pex(pex_ex_t * pex) {
- fs_node_t * fnode = malloc(sizeof(fs_node_t));
- memset(fnode, 0x00, sizeof(fs_node_t));
- fnode->inode = 0;
- strcpy(fnode->name, pex->name);
- fnode->device = pex;
- fnode->mask = 0666;
- fnode->flags = FS_CHARDEVICE;
- fnode->open = open_pex;
- fnode->read = read_server;
- fnode->write = write_server;
- return fnode;
- }
- static fs_node_t * finddir_packetfs(fs_node_t * node, char * name) {
- if (!name) return NULL;
- pex_t * p = (pex_t *)node->device;
- debug_print(INFO, "[pex] finddir(%s)", name);
- spin_lock(p->lock);
- foreach(f, p->exchanges) {
- pex_ex_t * t = (pex_ex_t *)f->value;
- if (!strcmp(name, t->name)) {
- spin_unlock(p->lock);
- return file_from_pex(t);
- }
- }
- spin_unlock(p->lock);
- return NULL;
- }
- static int create_packetfs(fs_node_t *parent, char *name, uint16_t permission) {
- if (!name) return -EINVAL;
- pex_t * p = (pex_t *)parent->device;
- debug_print(NOTICE, "[pex] create(%s)", name);
- spin_lock(p->lock);
- foreach(f, p->exchanges) {
- pex_ex_t * t = (pex_ex_t *)f->value;
- if (!strcmp(name, t->name)) {
- spin_unlock(p->lock);
- /* Already exists */
- return -EEXIST;
- }
- }
- /* Make it */
- pex_ex_t * new_exchange = malloc(sizeof(pex_ex_t));
- new_exchange->name = strdup(name);
- new_exchange->fresh = 1;
- new_exchange->clients = list_create();
- new_exchange->server_pipe = make_pipe(4096);
- spin_init(new_exchange->lock);
- /* XXX Create exchange server pipe */
- list_insert(p->exchanges, new_exchange);
- spin_unlock(p->lock);
- return 0;
- }
- static void destroy_pex(pex_ex_t * p) {
- /* XXX */
- }
- static int unlink_packetfs(fs_node_t *parent, char *name) {
- if (!name) return -EINVAL;
- pex_t * p = (pex_t *)parent->device;
- debug_print(NOTICE, "[pex] unlink(%s)", name);
- int i = -1, j = 0;
- spin_lock(p->lock);
- foreach(f, p->exchanges) {
- pex_ex_t * t = (pex_ex_t *)f->value;
- if (!strcmp(name, t->name)) {
- destroy_pex(t);
- i = j;
- break;
- }
- j++;
- }
- if (i >= 0) {
- list_remove(p->exchanges, i);
- } else {
- spin_unlock(p->lock);
- return -ENOENT;
- }
- spin_unlock(p->lock);
- return 0;
- }
- static fs_node_t * packetfs_manager(void) {
- pex_t * pex = malloc(sizeof(pex_t));
- pex->exchanges = list_create();
- spin_init(pex->lock);
- fs_node_t * fnode = malloc(sizeof(fs_node_t));
- memset(fnode, 0x00, sizeof(fs_node_t));
- fnode->inode = 0;
- strcpy(fnode->name, "pex");
- fnode->device = pex;
- fnode->mask = 0777;
- fnode->flags = FS_DIRECTORY;
- fnode->readdir = readdir_packetfs;
- fnode->finddir = finddir_packetfs;
- fnode->create = create_packetfs;
- fnode->unlink = unlink_packetfs;
- return fnode;
- }
- static int init(void) {
- fs_node_t * packet_mgr = packetfs_manager();
- vfs_mount("/dev/pex", packet_mgr);
- return 0;
- }
- static int fini(void) {
- return 0;
- }
- MODULE_DEF(packetfs, init, fini);
|