/* * 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);}
/*
* 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 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);
}