| #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); |
| } |
| |