shithub: neoventi

Download patch

ref: e8ed35d914bdf4445a4e915ca361f6eb26bbd611
parent: a734ef4f09cf5c4b7851b17f88f2970607ee25b2
author: Noam Preil <noam@pixelhero.dev>
date: Sun Dec 24 12:05:53 EST 2023

hand errors to client

--- a/neoventi.h
+++ b/neoventi.h
@@ -108,10 +108,12 @@
 
 	MinMatch	= 3,		/* shortest match possible */
 
-	MinDecode	= 8,		/* minimum bits to decode a match or lit; >= 8 */
+	MinDecode	= 8,			/* minimum bits to decode a match or lit; >= 8 */
 
-	MaxSeqMask	= 8,		/* number of bits in coding block mask */
-	MaxSeqStart	= 256		/* max offset of initial coding block */
+	MaxSeqMask	= 8,	/* number of bits in coding block mask */
+	MaxSeqStart	= 256,	/* max offset of initial coding block */
+
+	MaxPacketSize = 0x10008, /* largest possible protocol message */
 }; 
 
 int	unwhack(uchar *dst, u16int dsize, uchar *src, u16int ssize);
--- a/server.c
+++ b/server.c
@@ -3,34 +3,55 @@
 #include <bio.h>
 #include "neoventi.h"
 
+
 // Handles an error on `conn` handling client request `tbuf`
 // Only the tag must be preserved in the buffer
 static void
 vterr(VtConn conn, char *tbuf, char *msg, ...)
 {
+	u16int len;
 	va_list args;
 	va_start(args, msg);
 	msg = vsmprint(msg, args);
 	werrstr(msg);
-	free(msg);
 	va_end(args);
 	if(tbuf != nil){
-		// TODO: send Rerror message
+		len = strlen(msg);
+		tbuf[2] = VtRerror;
+		tbuf[4] = len >> 8;
+		tbuf[5] = len & 0xFF;
+		memcpy(tbuf + 6, msg, len);
+		len += 4;
+		tbuf[0] = len >> 8;
+		tbuf[1] = len & 0xFF;
+		if(write(conn.fd, tbuf, len+2) != len+2)
+			fprint(2, "failed to report error: %r");
 	}
+	free(msg);
 	longjmp(conn.bounce, 1);
 }
 
+static void
+vthangup(VtConn conn)
+{
+	longjmp(conn.bounce, 2);
+}
+
 // Convenience function: reads a venti packet from conn into buf
-// Invariant: buf MUST have 0x10002 bytes available! see venti(6)
 static void
 vtrecv(VtConn conn, char *buf)
 {
 	u16int len;
-	if(read(conn.fd, buf, 2) != 2)
-		vterr(conn, nil, "failed to read message size: %r");
-	len = (buf[0] << 8 | buf[1]);
-	if(read(conn.fd, buf + 2, len) != len)
-		vterr(conn, nil, "failed to read message: %r");
+	switch(read(conn.fd, buf, 2)){
+	case 0:
+		vthangup(conn);
+	case 1:
+		vterr(conn, nil, "received a single byte for message size");
+	case 2:
+		len = (buf[0] << 8 | buf[1]);
+		if(read(conn.fd, buf + 2, len) != len)
+			vterr(conn, nil, "failed to read message: %r");
+	}
 }
 
 static void
@@ -55,19 +76,16 @@
 	u64int addr;
 	u16int size;
 	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");
+	buf[0] = (size+2)>>8;
+	buf[1] = (size+2) & 0xFF;
+	buf[2] = VtRread;
+	readclump((uchar*)buf+4, arena, addr, blocks);
+	if(write(conn.fd, buf, size + 4) != size+4)
+		vterr(conn, buf, "failed to write data");
 }
 
 static int
@@ -78,7 +96,7 @@
 		vtread(conn, buf);
 		return 1;
 	case VtTgoodbye:
-		return 0;
+		vthangup(conn);
 	case VtTsync:
 		vterr(conn, buf, "TODO: sync not supported yet");
 	default:
@@ -107,12 +125,19 @@
 static void
 handle(int ctl, char *dir)
 {
-	char buf[0x10002];
+	char buf[MaxPacketSize];
 	VtConn conn;
-	if(setjmp(conn.bounce) != 0){
+	switch(setjmp(conn.bounce)){
+	case 0:
+		break;
+	case 1:
 		fprint(2, "abandoning client: %r\n");
+	case 2:
 		close(conn.fd);
 		return;
+	default:
+		fprint(2, "internal error: unexpected bounce code\n");
+		break;
 	}
 	conn.fd = accept(ctl, dir);
 	if(conn.fd < 0)
@@ -120,7 +145,10 @@
 	vthello(conn, buf);
 	while(1){
 		vtrecv(conn, buf);
-		vtconnhandle(conn, buf);
+		if(!vtconnhandle(conn, buf)){
+			close(conn.fd);
+			return;
+		}
 	}
 }
 
@@ -139,4 +167,4 @@
 		close(ctl);
 	}
 	fprint(2, "server has died\n");
-}
\ No newline at end of file
+}