Rudimentary packetfs
This commit is contained in:
parent
8b64e2b7d9
commit
272afa1999
1
Makefile
1
Makefile
@ -57,6 +57,7 @@ BOOT_MODULES += ext2
|
||||
BOOT_MODULES += debug_shell
|
||||
BOOT_MODULES += ps2mouse ps2kbd
|
||||
BOOT_MODULES += lfbvideo
|
||||
BOOT_MODULES += packetfs
|
||||
|
||||
# This is kinda silly. We're going to form an -initrd argument..
|
||||
# which is basically -initrd "hdd/mod/%.ko,hdd/mod/%.ko..."
|
||||
|
375
modules/packetfs.c
Normal file
375
modules/packetfs.c
Normal file
@ -0,0 +1,375 @@
|
||||
#include <system.h>
|
||||
#include <fs.h>
|
||||
#include <pipe.h>
|
||||
#include <module.h>
|
||||
#include <logging.h>
|
||||
|
||||
#define MAX_PACKET_SIZE 1024
|
||||
|
||||
typedef struct packet_manager {
|
||||
/* uh, nothing, lol */
|
||||
list_t * exchanges;
|
||||
volatile uint8_t lock;
|
||||
} pex_t;
|
||||
|
||||
typedef struct packet_exchange {
|
||||
char * name;
|
||||
char fresh;
|
||||
volatile uint8_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));
|
||||
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);
|
||||
|
||||
memcpy(packet->data, data, size);
|
||||
packet->source = c;
|
||||
packet->size = size;
|
||||
|
||||
write_fs(p->server_pipe, 0, p_size, (uint8_t *)packet);
|
||||
|
||||
free(packet);
|
||||
}
|
||||
|
||||
static void send_to_client(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);
|
||||
|
||||
memcpy(packet->data, data, size);
|
||||
packet->source = NULL;
|
||||
packet->size = size;
|
||||
|
||||
write_fs(c->pipe, 0, p_size, (uint8_t *)packet);
|
||||
|
||||
free(packet);
|
||||
|
||||
}
|
||||
|
||||
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, uint32_t offset, uint32_t size, uint8_t * buffer) {
|
||||
pex_ex_t * p = (pex_ex_t *)node->device;
|
||||
debug_print(WARNING, "[pex] server read(...)");
|
||||
debug_print(NOTICE, "fs_node = 0x%x\n", node);
|
||||
|
||||
packet_t * packet;
|
||||
|
||||
receive_packet(p->server_pipe, &packet);
|
||||
|
||||
debug_print(NOTICE, "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, uint32_t offset, uint32_t size, uint8_t * buffer) {
|
||||
pex_ex_t * p = (pex_ex_t *)node->device;
|
||||
debug_print(WARNING, "[pex] server write(...)");
|
||||
debug_print(NOTICE, "fs_node = 0x%x\n", node);
|
||||
|
||||
header_t * head = (header_t *)buffer;
|
||||
|
||||
if (size - sizeof(header_t) > MAX_PACKET_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (head->target == NULL) {
|
||||
/* Brodcast packet */
|
||||
foreach(f, p->clients) {
|
||||
send_to_client(p, (pex_client_t *)f->value, size - sizeof(header_t), &head->data);
|
||||
}
|
||||
} else if (head->target->parent != p) {
|
||||
debug_print(ERROR, "[pex] Invalid packet from server?");
|
||||
return -1;
|
||||
}
|
||||
|
||||
send_to_client(p, head->target, size - sizeof(header_t), &head->data);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static uint32_t read_client(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t * buffer) {
|
||||
pex_client_t * c = (pex_client_t *)node->inode;
|
||||
assert(c->parent == node->device);
|
||||
|
||||
debug_print(WARNING, "[pex] client read(...)");
|
||||
|
||||
packet_t * packet;
|
||||
|
||||
receive_packet(c->pipe, &packet);
|
||||
|
||||
if (packet->size > size) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(buffer, &packet->data, packet->size);
|
||||
uint32_t out = packet->size;
|
||||
|
||||
free(packet);
|
||||
return out;
|
||||
}
|
||||
|
||||
static uint32_t write_client(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t * buffer) {
|
||||
pex_client_t * c = (pex_client_t *)node->inode;
|
||||
assert(c->parent == node->device);
|
||||
|
||||
debug_print(WARNING, "[pex] client write(...)");
|
||||
|
||||
if (size > MAX_PACKET_SIZE) {
|
||||
debug_print(NOTICE, "Size of %d is too big.", size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
debug_print(NOTICE, "Sending packet of size %d to parent", size);
|
||||
send_to_server(c->parent, c, size, buffer);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static void open_pex(fs_node_t * node, unsigned int flags) {
|
||||
pex_ex_t * t = (pex_ex_t *)(node->device);
|
||||
|
||||
debug_print(WARNING, "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;
|
||||
debug_print(NOTICE, "[pex] Server launched: %s", t->name);
|
||||
debug_print(NOTICE, "fs_node = 0x%x\n", 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;
|
||||
|
||||
/* XXX: Send plumbing message to server for new client connection */
|
||||
debug_print(NOTICE, "[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(WARNING, "[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->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(WARNING, "[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 void create_packetfs(fs_node_t *parent, char *name, uint16_t permission) {
|
||||
if (!name) return;
|
||||
|
||||
pex_t * p = (pex_t *)parent->device;
|
||||
|
||||
debug_print(WARNING, "[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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make it */
|
||||
pex_ex_t * new_exchange = malloc(sizeof(pex_ex_t));
|
||||
|
||||
new_exchange->name = strdup(name);
|
||||
new_exchange->fresh = 1;
|
||||
new_exchange->lock = 0;
|
||||
new_exchange->clients = list_create();
|
||||
new_exchange->server_pipe = make_pipe(4096);
|
||||
/* XXX Create exchange server pipe */
|
||||
|
||||
list_insert(p->exchanges, new_exchange);
|
||||
|
||||
spin_unlock(&p->lock);
|
||||
|
||||
}
|
||||
|
||||
static void destroy_pex(pex_ex_t * p) {
|
||||
/* XXX */
|
||||
}
|
||||
|
||||
static void unlink_packetfs(fs_node_t *parent, char *name) {
|
||||
if (!name) return;
|
||||
|
||||
pex_t * p = (pex_t *)parent->device;
|
||||
|
||||
debug_print(WARNING, "[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);
|
||||
}
|
||||
|
||||
spin_unlock(&p->lock);
|
||||
}
|
||||
|
||||
static fs_node_t * packetfs_manager(void) {
|
||||
pex_t * pex = malloc(sizeof(pex_t));
|
||||
pex->exchanges = list_create();
|
||||
pex->lock = 0;
|
||||
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->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);
|
45
userspace/tests/test-pex.c
Normal file
45
userspace/tests/test-pex.c
Normal file
@ -0,0 +1,45 @@
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct packet {
|
||||
uintptr_t source;
|
||||
size_t size;
|
||||
uint8_t data[];
|
||||
} packet_t;
|
||||
#define MAX_PACKET_SIZE 1024
|
||||
#define PACKET_SIZE (sizeof(packet_t) + MAX_PACKET_SIZE)
|
||||
|
||||
typedef struct server_write_header {
|
||||
uintptr_t target;
|
||||
uint8_t data[];
|
||||
} header_t;
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
FILE * server = fopen("/dev/pex/testex", "a+");
|
||||
FILE * client = fopen("/dev/pex/testex", "r+");
|
||||
|
||||
/* Output is unbuffered so we can write packets discreetly */
|
||||
setbuf(server, NULL);
|
||||
setbuf(client, NULL);
|
||||
|
||||
fprintf(stdout, "[server = %p]\n", server);
|
||||
fprintf(stdout, "[client = %p]\n", client);
|
||||
|
||||
fprintf(client, "Hello World!");
|
||||
|
||||
packet_t * p = malloc(PACKET_SIZE);
|
||||
memset(p, 0x00, PACKET_SIZE);
|
||||
fprintf(stdout, "Reading %d...\n", PACKET_SIZE);
|
||||
size_t size = read(fileno(server), p, PACKET_SIZE);
|
||||
|
||||
fprintf(stdout, "Received a packet of size %d (%d) from client [0x%x]\n", p->size, size, p->source);
|
||||
fprintf(stdout, "Packet contents: %s\n", p->data);
|
||||
|
||||
|
||||
fclose(client);
|
||||
fclose(server);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user