| #include <u.h> | 
 | #include <libc.h> | 
 | #include <venti.h> | 
 | #include <thread.h> | 
 | #include "queue.h" | 
 |  | 
 | enum | 
 | { | 
 | 	STACK = 8192 | 
 | }; | 
 |  | 
 | typedef struct VtSconn VtSconn; | 
 | struct VtSconn | 
 | { | 
 | 	int ctl; | 
 | 	int ref; | 
 | 	QLock lk; | 
 | 	char dir[NETPATHLEN]; | 
 | 	VtSrv *srv; | 
 | 	VtConn *c; | 
 | }; | 
 |  | 
 | struct VtSrv | 
 | { | 
 | 	int afd; | 
 | 	int dead; | 
 | 	char adir[NETPATHLEN]; | 
 | 	Queue *q;	/* Queue(VtReq*) */ | 
 | }; | 
 |  | 
 | static void listenproc(void*); | 
 | static void connproc(void*); | 
 |  | 
 | char *VtServerLog = "libventi/server"; | 
 |  | 
 | static void | 
 | scincref(VtSconn *sc) | 
 | { | 
 | 	qlock(&sc->lk); | 
 | 	sc->ref++; | 
 | 	qunlock(&sc->lk); | 
 | } | 
 |  | 
 | static void | 
 | scdecref(VtSconn *sc) | 
 | { | 
 | 	qlock(&sc->lk); | 
 | 	if(--sc->ref > 0){ | 
 | 		qunlock(&sc->lk); | 
 | 		return; | 
 | 	} | 
 | 	if(sc->c) | 
 | 		vtfreeconn(sc->c); | 
 | 	vtfree(sc); | 
 | } | 
 |  | 
 | VtSrv* | 
 | vtlisten(char *addr) | 
 | { | 
 | 	VtSrv *s; | 
 |  | 
 | 	s = vtmallocz(sizeof(VtSrv)); | 
 | 	s->afd = announce(addr, s->adir); | 
 | 	if(s->afd < 0){ | 
 | 		free(s); | 
 | 		return nil; | 
 | 	} | 
 | 	s->q = _vtqalloc(); | 
 | 	proccreate(listenproc, s, STACK); | 
 | 	return s; | 
 | } | 
 |  | 
 | static void | 
 | listenproc(void *v) | 
 | { | 
 | 	int ctl; | 
 | 	char dir[NETPATHLEN]; | 
 | 	VtSrv *srv; | 
 | 	VtSconn *sc; | 
 |  | 
 | 	srv = v; | 
 | 	for(;;){ | 
 | 		ctl = listen(srv->adir, dir); | 
 | 		if(ctl < 0){ | 
 | 			srv->dead = 1; | 
 | 			break; | 
 | 		} | 
 | 		sc = vtmallocz(sizeof(VtSconn)); | 
 | 		sc->ref = 1; | 
 | 		sc->ctl = ctl; | 
 | 		sc->srv = srv; | 
 | 		strcpy(sc->dir, dir); | 
 | 		proccreate(connproc, sc, STACK); | 
 | 	} | 
 |  | 
 | 	/* hangup */ | 
 | } | 
 |  | 
 | static void | 
 | connproc(void *v) | 
 | { | 
 | 	VtSconn *sc; | 
 | 	VtConn *c; | 
 | 	Packet *p; | 
 | 	VtReq *r; | 
 | 	int fd; | 
 | static int first=1; | 
 |  | 
 | if(first && chattyventi){ | 
 | 	first=0; | 
 | 	fmtinstall('F', vtfcallfmt); | 
 | } | 
 | 	r = nil; | 
 | 	sc = v; | 
 | 	sc->c = nil; | 
 | 	if(0) fprint(2, "new call %s on %d\n", sc->dir, sc->ctl); | 
 | 	fd = accept(sc->ctl, sc->dir); | 
 | 	close(sc->ctl); | 
 | 	if(fd < 0){ | 
 | 		fprint(2, "accept %s: %r\n", sc->dir); | 
 | 		goto out; | 
 | 	} | 
 |  | 
 | 	c = vtconn(fd, fd); | 
 | 	sc->c = c; | 
 | 	if(vtversion(c) < 0){ | 
 | 		fprint(2, "vtversion %s: %r\n", sc->dir); | 
 | 		goto out; | 
 | 	} | 
 | 	if(vtsrvhello(c) < 0){ | 
 | 		fprint(2, "vtsrvhello %s: %r\n", sc->dir); | 
 | 		goto out; | 
 | 	} | 
 |  | 
 | 	if(0) fprint(2, "new proc %s\n", sc->dir); | 
 | 	proccreate(vtsendproc, c, STACK); | 
 | 	qlock(&c->lk); | 
 | 	while(!c->writeq) | 
 | 		rsleep(&c->rpcfork); | 
 | 	qunlock(&c->lk); | 
 |  | 
 | 	while((p = vtrecv(c)) != nil){ | 
 | 		r = vtmallocz(sizeof(VtReq)); | 
 | 		if(vtfcallunpack(&r->tx, p) < 0){ | 
 | 			vtlog(VtServerLog, "<font size=-1>%T %s:</font> recv bad packet %p: %r<br>\n", c->addr, p); | 
 | 			fprint(2, "bad packet on %s: %r\n", sc->dir); | 
 | 			packetfree(p); | 
 | 			continue; | 
 | 		} | 
 | 		vtlog(VtServerLog, "<font size=-1>%T %s:</font> recv packet %p (%F)<br>\n", c->addr, p, &r->tx); | 
 | 		if(chattyventi) | 
 | 			fprint(2, "%s <- %F\n", argv0, &r->tx); | 
 | 		packetfree(p); | 
 | 		if(r->tx.msgtype == VtTgoodbye) | 
 | 			break; | 
 | 		r->rx.tag = r->tx.tag; | 
 | 		r->sc = sc; | 
 | 		scincref(sc); | 
 | 		if(_vtqsend(sc->srv->q, r) < 0){ | 
 | 			scdecref(sc); | 
 | 			fprint(2, "hungup queue\n"); | 
 | 			break; | 
 | 		} | 
 | 		r = nil; | 
 | 	} | 
 |  | 
 | 	if(0) fprint(2, "eof on %s\n", sc->dir); | 
 |  | 
 | out: | 
 | 	if(r){ | 
 | 		vtfcallclear(&r->tx); | 
 | 		vtfree(r); | 
 | 	} | 
 | 	if(0) fprint(2, "freed %s\n", sc->dir); | 
 | 	scdecref(sc); | 
 | 	return; | 
 | } | 
 |  | 
 | VtReq* | 
 | vtgetreq(VtSrv *srv) | 
 | { | 
 | 	VtReq *r; | 
 | 	 | 
 | 	r = _vtqrecv(srv->q); | 
 | 	if (r != nil) | 
 | 		vtlog(VtServerLog, "<font size=-1>%T %s:</font> vtgetreq %F<br>\n", ((VtSconn*)r->sc)->c->addr, &r->tx); | 
 | 	return r; | 
 | } | 
 |  | 
 | void | 
 | vtrespond(VtReq *r) | 
 | { | 
 | 	Packet *p; | 
 | 	VtSconn *sc; | 
 |  | 
 | 	sc = r->sc; | 
 | 	if(r->rx.tag != r->tx.tag) | 
 | 		abort(); | 
 | 	if(r->rx.msgtype != r->tx.msgtype+1 && r->rx.msgtype != VtRerror) | 
 | 		abort(); | 
 | 	if(chattyventi) | 
 | 		fprint(2, "%s -> %F\n", argv0, &r->rx); | 
 | 	if((p = vtfcallpack(&r->rx)) == nil){ | 
 | 		vtlog(VtServerLog, "%s: vtfcallpack %F: %r<br>\n", sc->c->addr, &r->rx); | 
 | 		fprint(2, "fcallpack on %s: %r\n", sc->dir); | 
 | 		packetfree(p); | 
 | 		vtfcallclear(&r->rx); | 
 | 		return; | 
 | 	} | 
 | 	vtlog(VtServerLog, "<font size=-1>%T %s:</font> send packet %p (%F)<br>\n", sc->c->addr, p, &r->rx); | 
 | 	if(vtsend(sc->c, p) < 0) | 
 | 		fprint(2, "vtsend %F: %r\n", &r->rx); | 
 | 	scdecref(sc); | 
 | 	vtfcallclear(&r->tx); | 
 | 	vtfcallclear(&r->rx); | 
 | 	vtfree(r); | 
 | } | 
 |  |