shithub: neoventi

ref: 8a603a071dc58deb4ab66b76572c5a82767fa8db
dir: /server.c/

View raw version
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "neoventi.h"

// Convenience function: reads a venti packed from conn into buf
// Invariant: buf MUST have 0x10002 bytes available! see venti(6)
static int
vtrecv(VtConn conn, char *buf)
{
	u16int len;
	if(read(conn.fd, buf, 2) != 2){
		werrstr("Failed to read message size: %r");
		return 0;
	}
	len = (buf[0] << 8 | buf[1]);
	if(read(conn.fd, buf + 2, len) != len){
		werrstr("Failed to read message: %r");
		return 0;
	}
	return 1;
}

static void
vtversion(VtConn conn)
{
	char c;
	if(fprint(conn.fd, "venti-02-neoventi\n") == 18)
		while(read(conn.fd, &c, 1) == 1)
			if(c == '\n')
				return;
	fprint(conn.fd, "FUCK OFF\n");
	close(conn.fd);
	sysfatal("venti handshake failed: %r");
}

static void
vtread(VtConn conn, char *buf)
{
	u8int *score;
	VtArena arena;
	u64int addr;
	u16int size;
	u32int off;
	u8int blocks;
	uchar *dbuf;
	score = (u8int*)buf + 4;
	if(!vtreadlookup(score, &arena, &addr, &size, &blocks))
		sysfatal("todo graceful read errors");
	// Response: VtRread, msg tag, data
	dbuf = malloc(4 + size);
	dbuf[0] = (size+2)>>8;
	dbuf[1] = (size+2) & 0xFF;
	dbuf[2] = VtRread;
	dbuf[3] = buf[3];
	readclump(dbuf+4, arena, addr, blocks);
	if(write(conn.fd, dbuf, size + 4) != size+4)
		sysfatal("failed to write data");
}

static int
vtconnhandle(VtConn conn, char *buf)
{
	switch(buf[2]){
	case VtTread:
		vtread(conn, buf);
		return 1;
	case VtTgoodbye:
		return 0;
	case VtTsync:
		print("we don't support vtsync yet. Hanging up!\n");
		return 0;
	default:
		sysfatal("TODO safely hang up vtconns");
	}
	return 0;
}

static void
handle(int ctl, char *dir)
{
	char buf[0x10002];
	VtConn conn;
	conn.fd = accept(ctl, dir);
	if(conn.fd < 0)
		sysfatal("failed to accept connection: %r");
	print("received a connection at %s, fd %d\n", dir, conn.fd);
	vtversion(conn);
	if(!vtrecv(conn, buf))
		sysfatal("msg recv failed: %r");
	if(buf[2] != VtThello)
		sysfatal("received message before hello: %d", buf[2]);
	if(buf[4] != 0 || buf[5] != 2 || buf[6] != '0' || buf[7] != '2')
		sysfatal("unsupported protocol version requested in Thello: %d %d %d %d", buf[4], buf[5], buf[6], buf[7]);
	buf[2] = VtRhello;
	buf[6] = 'n';
	buf[7] = 'o';
	buf[1] = 8;
	if(write(conn.fd, buf, 10) != 10)
		sysfatal("failed to rhello: %r");
	while(vtrecv(conn, buf)){
		if(!vtconnhandle(conn, buf))
			break;
	}
	close(conn.fd);
}

void
serve(char *addr)
{
	char adir[NETPATHLEN], dir[NETPATHLEN];
	int fd, ctl;
	fd = announce(addr, adir);
	if(fd < 0)
		sysfatal("%r");
	procsetname("neoventi/server");
	for(ctl = listen(adir, dir); ctl >= 0; ctl = listen(adir, dir)){
		handle(ctl, dir);
		close(ctl);
	}
	fprint(2, "server has died\n");
}