plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

server.c (3747B)


      1 #include <u.h>
      2 #include <libc.h>
      3 #include <venti.h>
      4 #include <thread.h>
      5 #include "queue.h"
      6 
      7 enum
      8 {
      9 	STACK = 8192
     10 };
     11 
     12 typedef struct VtSconn VtSconn;
     13 struct VtSconn
     14 {
     15 	int ctl;
     16 	int ref;
     17 	QLock lk;
     18 	char dir[NETPATHLEN];
     19 	VtSrv *srv;
     20 	VtConn *c;
     21 };
     22 
     23 struct VtSrv
     24 {
     25 	int afd;
     26 	int dead;
     27 	char adir[NETPATHLEN];
     28 	Queue *q;	/* Queue(VtReq*) */
     29 };
     30 
     31 static void listenproc(void*);
     32 static void connproc(void*);
     33 
     34 char *VtServerLog = "libventi/server";
     35 
     36 static void
     37 scincref(VtSconn *sc)
     38 {
     39 	qlock(&sc->lk);
     40 	sc->ref++;
     41 	qunlock(&sc->lk);
     42 }
     43 
     44 static void
     45 scdecref(VtSconn *sc)
     46 {
     47 	qlock(&sc->lk);
     48 	if(--sc->ref > 0){
     49 		qunlock(&sc->lk);
     50 		return;
     51 	}
     52 	if(sc->c)
     53 		vtfreeconn(sc->c);
     54 	vtfree(sc);
     55 }
     56 
     57 VtSrv*
     58 vtlisten(char *addr)
     59 {
     60 	VtSrv *s;
     61 
     62 	s = vtmallocz(sizeof(VtSrv));
     63 	s->afd = announce(addr, s->adir);
     64 	if(s->afd < 0){
     65 		free(s);
     66 		return nil;
     67 	}
     68 	s->q = _vtqalloc();
     69 	proccreate(listenproc, s, STACK);
     70 	return s;
     71 }
     72 
     73 static void
     74 listenproc(void *v)
     75 {
     76 	int ctl;
     77 	char dir[NETPATHLEN];
     78 	VtSrv *srv;
     79 	VtSconn *sc;
     80 
     81 	srv = v;
     82 	for(;;){
     83 		ctl = listen(srv->adir, dir);
     84 		if(ctl < 0){
     85 			srv->dead = 1;
     86 			break;
     87 		}
     88 		sc = vtmallocz(sizeof(VtSconn));
     89 		sc->ref = 1;
     90 		sc->ctl = ctl;
     91 		sc->srv = srv;
     92 		strcpy(sc->dir, dir);
     93 		proccreate(connproc, sc, STACK);
     94 	}
     95 
     96 	/* hangup */
     97 }
     98 
     99 static void
    100 connproc(void *v)
    101 {
    102 	VtSconn *sc;
    103 	VtConn *c;
    104 	Packet *p;
    105 	VtReq *r;
    106 	int fd;
    107 static int first=1;
    108 
    109 if(first && chattyventi){
    110 	first=0;
    111 	fmtinstall('F', vtfcallfmt);
    112 }
    113 	r = nil;
    114 	sc = v;
    115 	sc->c = nil;
    116 	if(0) fprint(2, "new call %s on %d\n", sc->dir, sc->ctl);
    117 	fd = accept(sc->ctl, sc->dir);
    118 	close(sc->ctl);
    119 	if(fd < 0){
    120 		fprint(2, "accept %s: %r\n", sc->dir);
    121 		goto out;
    122 	}
    123 
    124 	c = vtconn(fd, fd);
    125 	sc->c = c;
    126 	if(vtversion(c) < 0){
    127 		fprint(2, "vtversion %s: %r\n", sc->dir);
    128 		goto out;
    129 	}
    130 	if(vtsrvhello(c) < 0){
    131 		fprint(2, "vtsrvhello %s: %r\n", sc->dir);
    132 		goto out;
    133 	}
    134 
    135 	if(0) fprint(2, "new proc %s\n", sc->dir);
    136 	proccreate(vtsendproc, c, STACK);
    137 	qlock(&c->lk);
    138 	while(!c->writeq)
    139 		rsleep(&c->rpcfork);
    140 	qunlock(&c->lk);
    141 
    142 	while((p = vtrecv(c)) != nil){
    143 		r = vtmallocz(sizeof(VtReq));
    144 		if(vtfcallunpack(&r->tx, p) < 0){
    145 			vtlog(VtServerLog, "<font size=-1>%T %s:</font> recv bad packet %p: %r<br>\n", c->addr, p);
    146 			fprint(2, "bad packet on %s: %r\n", sc->dir);
    147 			packetfree(p);
    148 			continue;
    149 		}
    150 		vtlog(VtServerLog, "<font size=-1>%T %s:</font> recv packet %p (%F)<br>\n", c->addr, p, &r->tx);
    151 		if(chattyventi)
    152 			fprint(2, "%s <- %F\n", argv0, &r->tx);
    153 		packetfree(p);
    154 		if(r->tx.msgtype == VtTgoodbye)
    155 			break;
    156 		r->rx.tag = r->tx.tag;
    157 		r->sc = sc;
    158 		scincref(sc);
    159 		if(_vtqsend(sc->srv->q, r) < 0){
    160 			scdecref(sc);
    161 			fprint(2, "hungup queue\n");
    162 			break;
    163 		}
    164 		r = nil;
    165 	}
    166 
    167 	if(0) fprint(2, "eof on %s\n", sc->dir);
    168 
    169 out:
    170 	if(r){
    171 		vtfcallclear(&r->tx);
    172 		vtfree(r);
    173 	}
    174 	if(0) fprint(2, "freed %s\n", sc->dir);
    175 	scdecref(sc);
    176 	return;
    177 }
    178 
    179 VtReq*
    180 vtgetreq(VtSrv *srv)
    181 {
    182 	VtReq *r;
    183 
    184 	r = _vtqrecv(srv->q);
    185 	if (r != nil)
    186 		vtlog(VtServerLog, "<font size=-1>%T %s:</font> vtgetreq %F<br>\n", ((VtSconn*)r->sc)->c->addr, &r->tx);
    187 	return r;
    188 }
    189 
    190 void
    191 vtrespond(VtReq *r)
    192 {
    193 	Packet *p;
    194 	VtSconn *sc;
    195 
    196 	sc = r->sc;
    197 	if(r->rx.tag != r->tx.tag)
    198 		abort();
    199 	if(r->rx.msgtype != r->tx.msgtype+1 && r->rx.msgtype != VtRerror)
    200 		abort();
    201 	if(chattyventi)
    202 		fprint(2, "%s -> %F\n", argv0, &r->rx);
    203 	if((p = vtfcallpack(&r->rx)) == nil){
    204 		vtlog(VtServerLog, "%s: vtfcallpack %F: %r<br>\n", sc->c->addr, &r->rx);
    205 		fprint(2, "fcallpack on %s: %r\n", sc->dir);
    206 		packetfree(p);
    207 		vtfcallclear(&r->rx);
    208 		return;
    209 	}
    210 	vtlog(VtServerLog, "<font size=-1>%T %s:</font> send packet %p (%F)<br>\n", sc->c->addr, p, &r->rx);
    211 	if(vtsend(sc->c, p) < 0)
    212 		fprint(2, "vtsend %F: %r\n", &r->rx);
    213 	scdecref(sc);
    214 	vtfcallclear(&r->tx);
    215 	vtfcallclear(&r->rx);
    216 	vtfree(r);
    217 }