ref: 2852fc75b203598e781db315ea6b2a7735d2db4a
parent: 3d91225b38e4e1a87b60e065c2f02c16ea0a8c1e
author: qwx <[email protected]>
date: Sat Mar 6 21:03:58 EST 2021
basic network protocol and communication - com.c: protocol/communication code - net.c now only deals with networking - make pause a request to the local server - fix not initializing buffer in kproc - give sim proc higher stack size, not main client communicates to the local server via a pipe, but transparently wrt the server. network data is read in separate procs and csp is used for communication and syncing. each connection has its own buffer which is blocked until parsed.
--- /dev/null
+++ b/com.c
@@ -1,0 +1,168 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <fcall.h>
+#include "dat.h"
+#include "fns.h"
+
+enum{
+ Hdrsz = 4,
+};
+typedef struct Header Header;
+struct Header{
+ int empty;
+};
+
+static int
+vpack(uchar *p, uchar *e, char *fmt, va_list a)
+{
+ int n, sz;
+ uchar u[8];
+ u32int v;
+ u64int w;
+
+ sz = 0;
+ for(;;){
+ n = 0;
+ switch(*fmt++){
+ default: sysfatal("unknown format %c", fmt[-1]);
+ copy: if(p + n > e) sysfatal("vpack: buffer overflow");
+ memcpy(p, u, n); p += n; break;
+ case 0: return sz;
+ case 'h': v = va_arg(a, int); PBIT8(u, v); n = sizeof(u8int); goto copy;
+ case 's': v = va_arg(a, int); PBIT16(u, v); n = sizeof(u16int); goto copy;
+ case 'l': v = va_arg(a, int); PBIT32(u, v); n = sizeof(u32int); goto copy;
+ case 'v': w = va_arg(a, vlong); PBIT64(u, w); n = sizeof(u64int); goto copy;
+ }
+ sz += n;
+ }
+}
+
+static int
+vunpack(uchar *p, uchar *e, char *fmt, va_list a)
+{
+ int n, sz;
+
+ sz = 0;
+ for(;;){
+ switch(*fmt++){
+ default: sysfatal("vunpack: unknown format %c", fmt[-1]);
+ error: werrstr("vunpack: truncated message"); return -1;
+ case 0: return sz;
+ case 'h': n = sizeof(u8int); if(p + n > e) goto error;
+ *va_arg(a, int*) = GBIT8(p); p += n;
+ break;
+ case 's': n = sizeof(u16int); if(p + n > e) goto error;
+ *va_arg(a, int*) = GBIT16(p); p += n;
+ break;
+ case 'l': n = sizeof(u32int); if(p + n > e) goto error;
+ *va_arg(a, int*) = GBIT32(p); p += n;
+ break;
+ case 'v': n = sizeof(u64int); if(p + n > e) goto error;
+ *va_arg(a, vlong*) = GBIT64(p); p += n;
+ break;
+ }
+ sz += n;
+ }
+}
+
+static int
+pack(uchar *p, uchar *e, char *fmt, ...)
+{
+ int n;
+ va_list a;
+
+ va_start(a, fmt);
+ n = vpack(p, e, fmt, a);
+ va_end(a);
+ return n;
+}
+
+static int
+unpack(uchar *p, uchar *e, char *fmt, ...)
+{
+ int n;
+ va_list a;
+
+ va_start(a, fmt);
+ n = vunpack(p, e, fmt, a);
+ va_end(a);
+ return n;
+}
+
+static int
+reqpause(uchar *p, uchar *e)
+{
+ int dicks;
+
+ if(unpack(p, e, "l", &dicks) < 0){
+ fprint(2, "reqpause: %r\n");
+ return -1;
+ }
+ pause ^= 1;
+ return 0;
+}
+
+static int
+readhdr(Msg *m, Header *h)
+{
+ USED(h);
+ if(m->sz <= Hdrsz)
+ return -1;
+ return 0;
+}
+
+int
+parsemsg(Msg *m)
+{
+ int n, type;
+ uchar *p, *e;
+ Header h;
+
+ if(readhdr(m, &h) < 0)
+ return -1;
+ p = m->buf + Hdrsz;
+ e = p + sizeof(m->buf) - Hdrsz;
+ while(p < e){
+ type = *p++;
+ switch(type){
+ case Tpause:
+ if((n = reqpause(p, e)) < 0){
+ dprint("parse: invalid Tpause: %r\n");
+ return -1;
+ }
+ break;
+ default:
+ dprint("parse: invalid message type %ux\n", type);
+ return -1;
+ }
+ p += n;
+ }
+ return 0;
+}
+
+static void
+newmsg(Msg *m)
+{
+ Header h;
+
+ USED(h);
+ m->sz += Hdrsz;
+}
+
+int
+sendpause(void)
+{
+ int n;
+ Msg *m;
+
+ m = getclbuf();
+ if(m->sz == 0)
+ newmsg(m);
+ if((n = pack(m->buf + m->sz, m->buf + sizeof m->buf, "hl", Tpause, 0)) < 0){
+ fprint(2, "sendpause: %r\n");
+ return -1;
+ }
+ m->sz += n;
+ return 0;
+}
--- a/dat.h
+++ b/dat.h
@@ -11,6 +11,8 @@
typedef struct Map Map;
typedef struct Resource Resource;
typedef struct Team Team;
+typedef struct Cbuf Cbuf;
+typedef struct Msg Msg;
enum{
Nresource = 3,
@@ -194,6 +196,17 @@
enum{
Tquit,
+ Tpause,
+
+ Nbuf = 4096,
+};
+struct Cbuf{
+ uchar buf[Nbuf];
+ int sz;
+};
+struct Msg{
+ Team *t;
+ Cbuf;
};
enum{
--- a/fns.h
+++ b/fns.h
@@ -1,3 +1,8 @@
+void clearmsg(Msg*);
+Msg* readnet(void);
+void initnet(char*);
+int parsemsg(Msg*);
+int sendpause(void);
void stepsnd(void);
void initsnd(void);
void linktomap(Mobj*);
@@ -7,9 +12,7 @@
void initsv(int, char*);
void flushcl(void);
void packcl(char*, ...);
-void stepnet(void);
-void joinnet(char*);
-void listennet(void);
+Msg* getclbuf(void);
void dopan(Point);
void select(Point);
void move(Point);
--- a/fs.c
+++ b/fs.c
@@ -111,7 +111,7 @@
continue;
}
if(pic0.h % Nteam != 0)
- sysfatal("loadobjpic: obj %s sprite sheet %d,%d: height not multiple of %d\n",
+ sysfatal("loadobjpic: obj %s sprite sheet %d,%d: height not multiple of %d",
pl->name, pic0.w, pic0.h, Nteam);
pic0.h /= Nteam;
n = pic0.w * pic0.h;
@@ -136,7 +136,7 @@
snprint(path, sizeof path, "%s.bit", tileset);
loadpic(path, &tilesetpic, 0);
if(tilesetpic.h % tilesetpic.w != 0)
- sysfatal("loadterpic: tiles not squares: tilepic %d,%d\n",
+ sysfatal("loadterpic: tiles not squares: tilepic %d,%d",
tilesetpic.w, tilesetpic.h);
}
id = pl->frm;
--- a/mkfile
+++ b/mkfile
@@ -3,6 +3,7 @@
TARG=sce
OFILES=\
bmap.$O\
+ com.$O\
drw.$O\
fs.$O\
map.$O\
--- a/net.c
+++ b/net.c
@@ -10,153 +10,119 @@
typedef struct Con Con;
enum{
- Ncon = Nteam * 4,
- Nbuf = 4096,
+ Ncon = Nteam * 2,
};
struct Con{
int fd;
- Team *t;
+ Msg;
+ Channel *waitc;
};
static Con con[Ncon];
-static Channel *lc;
-static uchar cbuf[Nbuf], *cbufp = cbuf;
+static Msg clbuf, sendbuf;
+Channel *conc;
+static int clpfd[2];
+
static void
closenet(Con *c)
{
close(c->fd);
c->fd = -1;
+ chanfree(c->waitc);
+ c->waitc = nil;
}
static void
-flushcmd(Con *c)
+flushreq(Con *c, Cbuf *cb)
{
- int n;
-
- if((n = cbufp - cbuf) == 0)
+ if(cb->sz == 0)
return;
- if(write(c->fd, cbuf, n) != n){
+ if(write(c->fd, cb->buf, cb->sz) != cb->sz){
fprint(2, "flushcmd: %r\n");
- closenet(c);
+ close(c->fd);
}
- cbufp = cbuf;
}
static void
-writecmd(Con *c, char *fmt, va_list a)
+writenet(void)
{
- union{
- uchar u[4];
- s32int l;
- } u;
+ Con *c;
- for(;;){
- if(cbufp - cbuf > sizeof(cbuf) - 4)
- flushcmd(c);
- switch(*fmt++){
- default: sysfatal("unknown format %c", fmt[-1]);
- case 0: return;
- case 'u':
- u.l = va_arg(a, s32int);
- memcpy(cbufp, u.u, sizeof u.u);
- cbufp += sizeof u.u;
- }
+ for(c=con; c<con+nelem(con); c++){
+ if(c->fd < 0)
+ continue;
+ flushreq(c, &sendbuf);
}
+ sendbuf.sz = 0;
}
-static void
-packcmd(Con *c, char *fmt, ...)
-{
- va_list a;
-
- va_start(a, fmt);
- writecmd(c, fmt, a);
- va_end(a);
-}
-
void
flushcl(void)
{
- flushcmd(con);
+ if(clbuf.sz == 0)
+ return;
+ write(clpfd[0], clbuf.buf, clbuf.sz);
+ clbuf.sz = 0;
}
void
-packcl(char *fmt, ...)
+clearmsg(Msg *m)
{
- va_list a;
+ Con *c;
- va_start(a, fmt);
- packcmd(con, fmt, a);
- va_end(a);
+ for(c=con; c<con+sizeof con; c++)
+ if(m == &c->Msg)
+ break;
+ assert(c < con + sizeof con);
+ m->sz = 0;
+ nbsendul(c->waitc, 0);
}
-static void
-writenet(void)
+Msg *
+readnet(void)
{
Con *c;
- for(c=con; c<con+nelem(con); c++){
- if(c->fd < 0)
- continue;
- }
+ if((c = nbrecvp(conc)) == nil)
+ return nil;
+ return &c->Msg;
}
-static void
-execbuf(Con *c, uchar *p, uchar *e)
+Msg *
+getclbuf(void)
{
- int n;
-
- while(p < e){
- n = *p++;
- switch(n){
- case Tquit: closenet(c); return;
- }
- }
+ return &clbuf;
}
static void
-readnet(void)
+conproc(void *cp)
{
- int n, m;
+ int n;
Con *c;
- uchar buf[Nbuf], *p;
- for(c=con; c<con+nelem(con); c++){
- if(c->fd < 0)
- continue;
- for(m=sizeof buf, p=buf; (n = flen(c->fd)) > 1 && n <= m; m-=n, p+=n){
- if(read(c->fd, p, n) != n){
- fprint(2, "readnet: %r\n");
- closenet(c);
- break;
- }
+ c = cp;
+ for(;;){
+ if((n = read(c->fd, c->buf, sizeof c->buf)) <= 0){
+ fprint(2, "cproc %zd: %r\n", c - con);
+ closenet(c);
+ return;
}
- execbuf(c, buf, p);
+ c->sz = n;
+ sendp(conc, c);
+ recvul(c->waitc);
+ c->sz = 0;
}
}
-void
-stepnet(void)
+static void
+initcon(Con *c)
{
- int fd;
-
- if(nbrecv(lc, &fd) > 0){
- /* FIXME: add to observers (team 0) */
- }
- readnet();
- writenet();
+ if((c->waitc = chancreate(sizeof(ulong), 0)) == nil)
+ sysfatal("chancreate: %r");
+ if(proccreate(conproc, c, 8192) < 0)
+ sysfatal("proccreate: %r");
}
-void
-joinnet(char *sys)
-{
- char s[128];
-
- snprint(s, sizeof s, "%s/tcp!%s!%d", netmtpt, sys != nil ? sys : sysname(), lport);
- if((con[0].fd = dial(s, nil, nil, nil)) < 0)
- sysfatal("dial: %r");
-}
-
static int
regnet(int lfd, char *ldir)
{
@@ -165,16 +131,19 @@
for(c=con; c<con+nelem(con); c++)
if(c->fd < 0)
break;
- if(c == con + nelem(con))
- return reject(lfd, ldir, "no more open slots");
+ if(c == con + nelem(con)){
+ reject(lfd, ldir, "no more open slots");
+ return -1;
+ }
c->fd = accept(lfd, ldir);
- return c->fd;
+ initcon(c);
+ return 0;
}
static void
-lproc(void *)
+listenproc(void *)
{
- int fd, lfd;
+ int lfd;
char adir[40], ldir[40], data[100];
snprint(data, sizeof data, "%s/tcp!*!%d", netmtpt, lport);
@@ -182,22 +151,46 @@
sysfatal("announce: %r");
for(;;){
if((lfd = listen(adir, ldir)) < 0
- || (fd = regnet(lfd, ldir)) < 0
- || close(lfd) < 0
- || send(lc, &fd) < 0)
+ || regnet(lfd, ldir) < 0
+ || close(lfd) < 0)
break;
}
}
-void
+static void
listennet(void)
{
+ if(proccreate(listenproc, nil, 8192) < 0)
+ sysfatal("proccreate: %r");
+}
+
+static void
+joinnet(char *sys)
+{
+ char s[128];
Con *c;
+ snprint(s, sizeof s, "%s/tcp!%s!%d", netmtpt, sys != nil ? sys : sysname(), lport);
+ c = &con[1];
+ if((c->fd = dial(s, nil, nil, nil)) < 0)
+ sysfatal("dial: %r");
+ initcon(c);
+}
+
+void
+initnet(char *sys)
+{
+ Con *c;
+
for(c=con; c<con+nelem(con); c++)
c->fd = -1;
- if((lc = chancreate(sizeof(int), 0)) == nil)
+ if((conc = chancreate(sizeof(uintptr), 1)) == nil)
sysfatal("chancreate: %r");
- if(proccreate(lproc, nil, 8192) < 0)
- sysfatal("proccreate: %r");
+ if(pipe(clpfd) < 0)
+ sysfatal("pipe: %r");
+ con[0].fd = clpfd[1];
+ initcon(&con[0]);
+ USED(sys);
+ //joinnet(sys);
+ //listennet();
}
--- a/sce.c
+++ b/sce.c
@@ -8,14 +8,12 @@
#include "dat.h"
#include "fns.h"
-mainstacksize = 16*1024;
-
enum{
Hz = 60,
};
char *progname = "sce", *dbname, *prefix, *mapname = "map1.db";
-int pause, debugmap;
+int debugmap;
QLock drawlock;
typedef struct Kev Kev;
@@ -80,6 +78,7 @@
if((fd = open("/dev/kbd", OREAD)) < 0)
sysfatal("kproc: %r");
memset(buf, 0, sizeof buf);
+ memset(down, 0, sizeof down);
for(;;){
if(buf[0] != 0){
n = strlen(buf)+1;
@@ -225,6 +224,7 @@
if(me.b & 4)
move(me);
qunlock(&drawlock);
+ flushcl();
break;
case Akbd:
if(ke.r == Kdel)
@@ -232,9 +232,10 @@
if(!ke.down)
continue;
switch(ke.r){
- case KF|1: debugmap ^= 1; pause ^= 1; break;
- case ' ': pause ^= 1; break;
+ case KF|1: debugmap ^= 1; break;
+ case ' ': sendpause(); break;
}
+ flushcl();
break;
case Atic:
updatefb();
--- a/sv.c
+++ b/sv.c
@@ -8,6 +8,7 @@
extern QLock drawlock;
vlong tc;
+int pause;
static int tdiv;
@@ -14,7 +15,13 @@
static void
step(vlong tics)
{
+ Msg *m;
+
qlock(&drawlock);
+ while((m = readnet()) != nil){
+ parsemsg(m);
+ clearmsg(m);
+ }
while(!pause && tics-- > 0)
stepsim();
qunlock(&drawlock);
@@ -25,7 +32,7 @@
{
vlong t, t0, dt, Δtc;
- USED(sys);
+ initnet(sys);
initsim();
Δtc = 1;
t0 = nsec();
@@ -47,6 +54,6 @@
initsv(int tv, char *sys)
{
tdiv = Te9 / (tv * 3);
- if(proccreate(simproc, sys, 8192) < 0)
+ if(proccreate(simproc, sys, 16*1024) < 0)
sysfatal("proccreate: %r");
}