226 lines · 4.0 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #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*); static voidscincref(VtSconn *sc){	qlock(&sc->lk);	sc->ref++;	qunlock(&sc->lk);} static voidscdecref(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 voidlistenproc(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 voidconnproc(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;} voidvtrespond(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);}