aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/9pserve.c
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2003-12-06 18:08:52 +0000
committerrsc <devnull@localhost>2003-12-06 18:08:52 +0000
commitd3df308747ee4d1fcc063a348dcf1146b390bda7 (patch)
treea204b027256ec29b110caaa86100cbd701808b5b /src/cmd/9pserve.c
parente97ceade5e1bba5787e39429384336fa37797906 (diff)
downloadplan9port-d3df308747ee4d1fcc063a348dcf1146b390bda7.tar.gz
plan9port-d3df308747ee4d1fcc063a348dcf1146b390bda7.tar.bz2
plan9port-d3df308747ee4d1fcc063a348dcf1146b390bda7.zip
File system stuff.
Diffstat (limited to 'src/cmd/9pserve.c')
-rw-r--r--src/cmd/9pserve.c597
1 files changed, 597 insertions, 0 deletions
diff --git a/src/cmd/9pserve.c b/src/cmd/9pserve.c
new file mode 100644
index 00000000..40db17e5
--- /dev/null
+++ b/src/cmd/9pserve.c
@@ -0,0 +1,597 @@
+#include <u.h>
+#include <libc.h>
+#include <fcall.h>
+#include <thread.h>
+
+enum
+{
+ STACK = 32768,
+ NHASH = 31,
+ MAXMSG = 64, /* per connection */
+};
+
+typedef struct Hash Hash;
+typedef struct Fid Fid;
+typedef struct Msg Msg;
+typedef struct Conn Conn;
+typedef struct Queue Queue;
+
+struct Hash
+{
+ Hash *next;
+ uint n;
+ void *v;
+};
+
+struct Fid
+{
+ int fid;
+ int ref;
+ int cfid;
+ Fid *next;
+};
+
+struct Msg
+{
+ Conn *c;
+ int internal;
+ int ref;
+ int ctag;
+ int tag;
+ Fcall tx;
+ Fcall rx;
+ Fid *fid;
+ Fid *newfid;
+ Fid *afid;
+ Msg *oldm;
+ Msg *next;
+ uchar *tpkt;
+ uchar *rpkt;
+};
+
+struct Conn
+{
+ int fd;
+ int nmsg;
+ int nfid;
+ Channel *inc;
+ Channel *internal;
+ int inputstalled;
+ char dir[40];
+ Hash *tag[NHASH];
+ Hash *fid[NHASH];
+ Queue *outq;
+ Queue *inq;
+};
+
+char *addr;
+int afd;
+char adir[40];
+int isunix;
+Queue *outq;
+Queue *inq;
+
+void *gethash(Hash**, uint);
+int puthash(Hash**, uint, void*);
+int delhash(Hash**, uint, void*);
+Msg *mread9p(int);
+int mwrite9p(int, Msg*);
+uchar *read9ppkt(int);
+int write9ppkt(int, uchar*);
+Msg *msgnew(void);
+void msgput(Msg*);
+Msg *msgget(int);
+Fid *fidnew(int);
+void fidput(Fid*);
+void *emalloc(int);
+void *erealloc(void*, int);
+int sendq(Queue*, void*);
+void *recvq(Queue*);
+void selectthread(void*);
+void connthread(void*);
+void listenthread(void*);
+void rewritehdr(Fcall*, uchar*);
+int tlisten(char*, char*);
+int taccept(int, char*);
+
+void
+usage(void)
+{
+ fprint(2, "usage: 9pserve [-u] address\n");
+ fprint(2, "\treads/writes 9P messages on stdin/stdout\n");
+ exits("usage");
+}
+
+void
+threadmain(int argc, char **argv)
+{
+ ARGBEGIN{
+ default:
+ usage();
+ case 'u':
+ isunix = 1;
+ break;
+ }ARGEND
+
+ if(argc != 1)
+ usage();
+
+ if((afd = announce(addr, adir)) < 0)
+ sysfatal("announce %s: %r", addr);
+
+ threadcreateidle(selectthread, nil, STACK);
+}
+
+void
+listenthread(void *arg)
+{
+ Conn *c;
+
+ USED(arg);
+ for(;;){
+ c = malloc(sizeof(Conn));
+ if(c == nil){
+ fprint(2, "out of memory\n");
+ sleep(60*1000);
+ continue;
+ }
+ c->fd = tlisten(adir, c->dir);
+ if(c->fd < 0){
+ fprint(2, "listen: %r\n");
+ close(afd);
+ free(c);
+ return;
+ }
+ threadcreate(connthread, c, STACK);
+ }
+}
+
+void
+err(Msg *m, char *ename)
+{
+ int n, nn;
+
+ m->rx.type = Rerror;
+ m->rx.ename = ename;
+ m->rx.tag = m->ctag;
+ n = sizeS2M(&m->rx);
+ m->rpkt = emalloc(n);
+ nn = convS2M(&m->rx, m->rpkt, n);
+ if(nn != n)
+ sysfatal("sizeS2M + convS2M disagree");
+ sendq(m->c->outq, m);
+}
+
+void
+connthread(void *arg)
+{
+ int i, fd;
+ Conn *c;
+ Hash *h;
+ Msg *m, *om;
+ Fid *f;
+
+ c = arg;
+ fd = taccept(c->fd, c->dir);
+ if(fd < 0){
+ fprint(2, "accept %s: %r\n", c->dir);
+ goto out;
+ }
+ close(c->fd);
+ c->fd = fd;
+ while((m = mread9p(c->fd)) != nil){
+ m->c = c;
+ c->nmsg++;
+ if(puthash(c->tag, m->tx.tag, m) < 0){
+ err(m, "duplicate tag");
+ continue;
+ }
+ switch(m->tx.type){
+ case Tflush:
+ if((m->oldm = gethash(c->tag, m->tx.oldtag)) == nil){
+ m->rx.tag = Rflush;
+ sendq(c->outq, m);
+ continue;
+ }
+ break;
+ case Tattach:
+ m->fid = fidnew(m->tx.fid);
+ if(puthash(c->fid, m->tx.fid, m->fid) < 0){
+ err(m, "duplicate fid");
+ continue;
+ }
+ m->fid->ref++;
+ break;
+ case Twalk:
+ if((m->fid = gethash(c->fid, m->tx.fid)) == nil){
+ err(m, "unknown fid");
+ continue;
+ }
+ if(m->tx.newfid == m->tx.fid){
+ m->fid->ref++;
+ m->newfid = m->fid;
+ }else{
+ m->newfid = fidnew(m->tx.newfid);
+ if(puthash(c->fid, m->tx.newfid, m->newfid) < 0){
+ err(m, "duplicate fid");
+ continue;
+ }
+ m->newfid->ref++;
+ }
+ break;
+ case Tauth:
+ if((m->afid = gethash(c->fid, m->tx.afid)) == nil){
+ err(m, "unknown fid");
+ continue;
+ }
+ m->fid = fidnew(m->tx.fid);
+ if(puthash(c->fid, m->tx.fid, m->fid) < 0){
+ err(m, "duplicate fid");
+ continue;
+ }
+ m->fid->ref++;
+ break;
+ case Topen:
+ case Tclunk:
+ case Tread:
+ case Twrite:
+ case Tstat:
+ case Twstat:
+ if((m->fid = gethash(c->fid, m->tx.fid)) == nil){
+ err(m, "unknown fid");
+ continue;
+ }
+ m->fid->ref++;
+ break;
+ }
+
+ /* have everything - translate and send */
+ m->c = c;
+ m->ctag = m->tx.tag;
+ m->tx.tag = m->tag;
+ if(m->fid)
+ m->tx.fid = m->fid->fid;
+ if(m->newfid)
+ m->tx.newfid = m->newfid->fid;
+ if(m->afid)
+ m->tx.afid = m->afid->fid;
+ if(m->oldm)
+ m->tx.oldtag = m->oldm->tag;
+ rewritehdr(&m->tx, m->tpkt);
+ sendq(outq, m);
+ while(c->nmsg >= MAXMSG){
+ c->inputstalled = 1;
+ recvp(c->inc);
+ }
+ }
+
+ /* flush all outstanding messages */
+ for(i=0; i<NHASH; i++){
+ for(h=c->tag[i]; h; h=h->next){
+ om = h->v;
+ m = msgnew();
+ m->internal = 1;
+ m->c = c;
+ m->tx.type = Tflush;
+ m->tx.tag = m->tag;
+ m->tx.oldtag = om->tag;
+ m->oldm = om;
+ om->ref++;
+ sendq(outq, m);
+ recvp(c->internal);
+ }
+ }
+
+ /* clunk all outstanding fids */
+ for(i=0; i<NHASH; i++){
+ for(h=c->fid[i]; h; h=h->next){
+ f = h->v;
+ m = msgnew();
+ m->internal = 1;
+ m->c = c;
+ m->tx.type = Tclunk;
+ m->tx.tag = m->tag;
+ m->tx.fid = f->fid;
+ m->fid = f;
+ f->ref++;
+ sendq(outq, m);
+ recvp(c->internal);
+ }
+ }
+
+out:
+ assert(c->nmsg == 0);
+ assert(c->nfid == 0);
+ close(c->fd);
+ free(c);
+}
+
+void
+connoutthread(void *arg)
+{
+ int err;
+ Conn *c;
+ Msg *m, *om;
+
+ c = arg;
+ while((m = recvq(c->outq)) != nil){
+ err = m->tx.type+1 != m->rx.type;
+ switch(m->tx.type){
+ case Tflush:
+ om = m->oldm;
+ if(delhash(om->c->tag, om->ctag, om) == 0)
+ msgput(om);
+ break;
+ case Tclunk:
+ if(delhash(m->c->fid, m->fid->cfid, m->fid) == 0)
+ fidput(m->fid);
+ break;
+ case Tauth:
+ if(err)
+ if(delhash(m->c->fid, m->afid->cfid, m->fid) == 0)
+ fidput(m->fid);
+ case Tattach:
+ if(err)
+ if(delhash(m->c->fid, m->fid->cfid, m->fid) == 0)
+ fidput(m->fid);
+ break;
+ case Twalk:
+ if(err && m->tx.fid != m->tx.newfid)
+ if(delhash(m->c->fid, m->newfid->cfid, m->newfid) == 0)
+ fidput(m->newfid);
+ break;
+ }
+ if(mwrite9p(c->fd, m) < 0)
+ fprint(2, "write error: %r\n");
+ if(delhash(m->c->tag, m->ctag, m) == 0)
+ msgput(m);
+ msgput(m);
+ if(c->inputstalled && c->nmsg < MAXMSG)
+ nbsendp(c->inc, 0);
+ }
+}
+
+void
+outputthread(void *arg)
+{
+ Msg *m;
+
+ USED(arg);
+
+ while((m = recvq(outq)) != nil){
+ if(mwrite9p(1, m) < 0)
+ sysfatal("output error: %r");
+ msgput(m);
+ }
+}
+
+void
+inputthread(void *arg)
+{
+ uchar *pkt;
+ int n, nn, tag;
+ Msg *m;
+
+ while((pkt = read9ppkt(0)) != nil){
+ n = GBIT32(pkt);
+ if(n < 7){
+ fprint(2, "short 9P packet\n");
+ free(pkt);
+ continue;
+ }
+ tag = GBIT16(pkt+5);
+ if((m = msgget(tag)) == nil){
+ fprint(2, "unexpected 9P response tag %d\n", tag);
+ free(pkt);
+ msgput(m);
+ continue;
+ }
+ if((nn = convM2S(pkt, n, &m->rx)) != n){
+ fprint(2, "bad packet - convM2S %d but %d\n", nn, n);
+ free(pkt);
+ msgput(m);
+ continue;
+ }
+ m->rpkt = pkt;
+ m->rx.tag = m->ctag;
+ rewritehdr(&m->rx, m->rpkt);
+ sendq(m->c->outq, m);
+ }
+}
+
+void*
+gethash(Hash **ht, uint n)
+{
+ Hash *h;
+
+ for(h=ht[n%NHASH]; h; h=h->next)
+ if(h->n == n)
+ return h->v;
+ return nil;
+}
+
+int
+delhash(Hash **ht, uint n, void *v)
+{
+ Hash *h, **l;
+
+ for(l=&ht[n%NHASH]; h=*l; l=&h->next)
+ if(h->n == n){
+ if(h->v != v)
+ fprint(2, "hash error\n");
+ *l = h->next;
+ free(h);
+ return 0;
+ }
+ return -1;
+}
+
+int
+puthash(Hash **ht, uint n, void *v)
+{
+ Hash *h;
+
+ if(gethash(ht, n))
+ return -1;
+ h = emalloc(sizeof(Hash));
+ h->next = ht[n%NHASH];
+ h->n = n;
+ h->v = v;
+ ht[n%NHASH] = h;
+ return 0;
+}
+
+Fid **fidtab;
+int nfidtab;
+Fid *freefid;
+
+Fid*
+fidnew(int cfid)
+{
+ Fid *f;
+
+ if(freefid == nil){
+ fidtab = erealloc(fidtab, nfidtab*sizeof(fidtab[0]));
+ fidtab[nfidtab] = emalloc(sizeof(Fid));
+ freefid = fidtab[nfidtab++];
+ }
+ f = freefid;
+ freefid = f->next;
+ f->cfid = f->cfid;
+ f->ref = 1;
+ return f;
+}
+
+void
+fidput(Fid *f)
+{
+ assert(f->ref > 0);
+ if(--f->ref > 0)
+ return;
+ f->next = freefid;
+ f->cfid = -1;
+ freefid = f;
+}
+
+Msg **msgtab;
+int nmsgtab;
+Msg *freemsg;
+
+Msg*
+msgnew(void)
+{
+ Msg *m;
+
+ if(freemsg == nil){
+ msgtab = erealloc(msgtab, nmsgtab*sizeof(msgtab[0]));
+ msgtab[nmsgtab] = emalloc(sizeof(Msg));
+ freemsg = msgtab[nmsgtab++];
+ }
+ m = freemsg;
+ freemsg = m->next;
+ m->ref = 1;
+ return m;
+}
+
+void
+msgput(Msg *m)
+{
+ assert(m->ref > 0);
+ if(--m->ref > 0)
+ return;
+ m->next = freemsg;
+ freemsg = m;
+}
+
+void*
+emalloc(int n)
+{
+ void *v;
+
+ v = mallocz(n, 1);
+ if(v == nil)
+ sysfatal("out of memory");
+ return v;
+}
+
+void*
+erealloc(void *v, int n)
+{
+ v = realloc(v, n);
+ if(v == nil)
+ sysfatal("out of memory");
+ return v;
+}
+
+typedef struct Qel Qel;
+struct Qel
+{
+ Qel *next;
+ void *p;
+};
+
+struct Queue
+{
+ int hungup;
+ QLock lk;
+ Rendez r;
+ Qel *head;
+ Qel *tail;
+};
+
+Queue*
+qalloc(void)
+{
+ Queue *q;
+
+ q = mallocz(sizeof(Queue), 1);
+ if(q == nil)
+ return nil;
+ q->r.l = &q->lk;
+ return q;
+}
+
+int
+sendq(Queue *q, void *p)
+{
+ Qel *e;
+
+ e = emalloc(sizeof(Qel));
+ qlock(&q->lk);
+ if(q->hungup){
+ werrstr("hungup queue");
+ qunlock(&q->lk);
+ return -1;
+ }
+ e->p = p;
+ e->next = nil;
+ if(q->head == nil)
+ q->head = e;
+ else
+ q->tail->next = e;
+ q->tail = e;
+ rwakeup(&q->r);
+ qunlock(&q->lk);
+ return 0;
+}
+
+void*
+recvq(Queue *q)
+{
+ void *p;
+ Qel *e;
+
+ qlock(&q->lk);
+ while(q->head == nil && !q->hungup)
+ rsleep(&q->r);
+ if(q->hungup){
+ qunlock(&q->lk);
+ return nil;
+ }
+ e = q->head;
+ q->head = e->next;
+ qunlock(&q->lk);
+ p = e->p;
+ free(e);
+ return p;
+}