void listenthread(void *arg) { Conn *c; Ioproc *io; io = ioproc(); USED(arg); threadsetname("listen %s", adir); for(;;){ c = emalloc(sizeof(Conn)); c->fd = iolisten(io, adir, c->dir); if(c->fd < 0){ if(verbose) fprint(2, "%T listen: %r\n"); close(afd); free(c); return; } c->inc = chancreate(sizeof(void*), 0); c->internal = chancreate(sizeof(void*), 0); c->inq = qalloc(); c->outq = qalloc(); c->outqdead = chancreate(sizeof(void*), 0); if(verbose) fprint(2, "%T incoming call on %s\n", c->dir); threadcreate(connthread, c, STACK); } }
int newclient(void) { int i; Client *c; for(i=0; i<nclient; i++) if(client[i]->ref==0 && !client[i]->moribund) return i; c = emalloc(sizeof(Client)); c->writerkick = chancreate(sizeof(void*), 1); c->execpid = chancreate(sizeof(ulong), 0); c->cmd = nocmd; c->readerproc = ioproc(); c->writerproc = ioproc(); c->num = nclient; if(nclient%16 == 0) client = erealloc(client, (nclient+16)*sizeof(client[0])); client[nclient++] = c; return nclient-1; }
static Ioproc* xioproc(void) { Ioproc *c; int i; for(i=0; i<ncache; i++){ if(c = cache[i]){ cache[i] = nil; return c; } } return ioproc(); }
void inputthread(void *arg) { uchar *pkt; int n, nn, tag; Msg *m; Ioproc *io; threadsetname("input"); if(verbose) fprint(2, "%T input thread\n"); io = ioproc(); USED(arg); while((pkt = read9ppkt(io, 0)) != nil){ n = GBIT32(pkt); if(n < 7){ fprint(2, "%T short 9P packet from server\n"); free(pkt); continue; } if(verbose > 2) fprint(2, "%T read %.*H\n", n, pkt); tag = GBIT16(pkt+5); if((m = msgget(tag)) == nil){ fprint(2, "%T unexpected 9P response tag %d\n", tag); free(pkt); continue; } if((nn = convM2S(pkt, n, &m->rx)) != n){ fprint(2, "%T bad packet - convM2S %d but %d\n", nn, n); free(pkt); msgput(m); continue; } if(verbose > 1) fprint(2, "%T * -> %F%s\n", &m->rx, m->internal ? " (internal)" : ""); m->rpkt = pkt; m->rx.tag = m->ctag; if(m->internal) sendp(m->c->internal, m); else if(m->c->outq) sendq(m->c->outq, m); else msgput(m); } closeioproc(io); /*fprint(2, "%T input eof\n"); */ threadexitsall(0); }
Fd* topen(int fd, int mode) { Fd *f; f = emalloc(sizeof *f); f->fd = fd; f->p = f->buf; f->mode = mode; f->io = ioproc(); f->r.l = &f->lk; if(mode == OREAD) f->ep = f->p; else{ spawn(twritethread, f); f->ep = f->buf+sizeof f->buf; } return f; }
void outputthread(void *arg) { Msg *m; Ioproc *io; USED(arg); io = ioproc(); threadsetname("output"); while((m = recvq(outq)) != nil){ if(m->sync){ sendp(m->c->outqdead, nil); continue; } if(verbose > 1) fprint(2, "%T * <- %F\n", &m->tx); rewritehdr(&m->tx, m->tpkt); if(mwrite9p(io, 1, m->tpkt) < 0) sysfatal("output error: %r"); msgput(m); } closeioproc(io); fprint(2, "%T output eof\n"); threadexitsall(0); }
void connoutthread(void *arg) { int err; Conn *c; Msg *m, *om; Ioproc *io; c = arg; io = ioproc(); threadsetname("connout %s", c->dir); while((m = recvq(c->outq)) != nil){ err = m->tx.type+1 != m->rx.type; if(!err && m->isopenfd) if(xopenfd(m) < 0) continue; switch(m->tx.type){ case Tflush: om = m->oldm; if(om) if(delhash(om->c->tag, om->ctag, om) == 0) msgput(om); break; case Tclunk: case Tremove: if(m->fid) if(delhash(m->c->fid, m->fid->cfid, m->fid) == 0) fidput(m->fid); break; case Tauth: if(err && m->afid){ if(verbose) fprint(2, "%T auth error\n"); if(delhash(m->c->fid, m->afid->cfid, m->afid) == 0) fidput(m->afid); } break; case Tattach: if(err && m->fid) if(delhash(m->c->fid, m->fid->cfid, m->fid) == 0) fidput(m->fid); break; case Twalk: if(err || m->rx.nwqid < m->tx.nwname) if(m->tx.fid != m->tx.newfid && m->newfid) if(delhash(m->c->fid, m->newfid->cfid, m->newfid) == 0) fidput(m->newfid); break; case Tread: break; case Tstat: break; case Topen: case Tcreate: m->fid->isdir = (m->rx.qid.type & QTDIR); break; } if(delhash(m->c->tag, m->ctag, m) == 0) msgput(m); if(verbose > 1) fprint(2, "%T fd#%d <- %F\n", c->fd, &m->rx); rewritehdr(&m->rx, m->rpkt); if(mwrite9p(io, c->fd, m->rpkt) < 0) if(verbose) fprint(2, "%T write error: %r\n"); msgput(m); if(c->inputstalled && c->nmsg < MAXMSG) nbsendp(c->inc, 0); } closeioproc(io); free(c->outq); c->outq = nil; sendp(c->outqdead, nil); }
static void openfdthread(void *v) { Conn *c; Fid *fid; Msg *m; int n; vlong tot; Ioproc *io; char buf[1024]; c = v; fid = c->fdfid; io = ioproc(); threadsetname("openfd %s", c->fdfid); tot = 0; m = nil; if(c->fdmode == OREAD){ for(;;){ if(verbose) fprint(2, "%T tread..."); m = msgnew(0); m->internal = 1; m->c = c; m->tx.type = Tread; m->tx.count = msize - IOHDRSZ; m->tx.fid = fid->fid; m->tx.tag = m->tag; m->tx.offset = tot; m->fid = fid; fid->ref++; msgincref(m); sendomsg(m); recvp(c->internal); if(m->rx.type == Rerror){ /* fprint(2, "%T read error: %s\n", m->rx.ename); */ break; } if(m->rx.count == 0) break; tot += m->rx.count; if(iowrite(io, c->fd, m->rx.data, m->rx.count) != m->rx.count){ /* fprint(2, "%T pipe write error: %r\n"); */ break; } msgput(m); msgput(m); m = nil; } }else{ for(;;){ if(verbose) fprint(2, "%T twrite..."); n = sizeof buf; if(n > msize) n = msize; if((n=ioread(io, c->fd, buf, n)) <= 0){ if(n < 0) fprint(2, "%T pipe read error: %r\n"); break; } m = msgnew(0); m->internal = 1; m->c = c; m->tx.type = Twrite; m->tx.fid = fid->fid; m->tx.data = buf; m->tx.count = n; m->tx.tag = m->tag; m->tx.offset = tot; m->fid = fid; fid->ref++; msgincref(m); sendomsg(m); recvp(c->internal); if(m->rx.type == Rerror){ /* fprint(2, "%T write error: %s\n", m->rx.ename); */ } tot += n; msgput(m); msgput(m); m = nil; } } if(verbose) fprint(2, "%T eof on %d fid %d\n", c->fd, fid->fid); close(c->fd); closeioproc(io); if(m){ msgput(m); msgput(m); } if(verbose) fprint(2, "%T eof on %d fid %d ref %d\n", c->fd, fid->fid, fid->ref); if(--fid->openfd == 0){ m = msgnew(0); m->internal = 1; m->c = c; m->tx.type = Tclunk; m->tx.tag = m->tag; m->tx.fid = fid->fid; m->fid = fid; fid->ref++; msgincref(m); sendomsg(m); recvp(c->internal); msgput(m); msgput(m); } fidput(fid); c->fdfid = nil; chanfree(c->internal); c->internal = 0; free(c); }
void connthread(void *arg) { int i, fd; Conn *c; Hash *h, *hnext; Msg *m, *om, *mm, sync; Fid *f; Ioproc *io; c = arg; threadsetname("conn %s", c->dir); io = ioproc(); fd = ioaccept(io, c->fd, c->dir); if(fd < 0){ if(verbose) fprint(2, "%T accept %s: %r\n", c->dir); goto out; } close(c->fd); c->fd = fd; threadcreate(connoutthread, c, STACK); while((m = mread9p(io, c->fd)) != nil){ if(verbose > 1) fprint(2, "%T fd#%d -> %F\n", c->fd, &m->tx); m->c = c; m->ctag = m->tx.tag; c->nmsg++; if(verbose > 1) fprint(2, "%T fd#%d: new msg %p\n", c->fd, m); if(puthash(c->tag, m->tx.tag, m) < 0){ err(m, "duplicate tag"); continue; } msgincref(m); switch(m->tx.type){ case Tversion: m->rx.tag = m->tx.tag; m->rx.msize = m->tx.msize; if(m->rx.msize > msize) m->rx.msize = msize; m->rx.version = "9P2000"; m->rx.type = Rversion; send9pmsg(m); continue; case Tflush: if((m->oldm = gethash(c->tag, m->tx.oldtag)) == nil){ m->rx.tag = m->tx.tag; m->rx.type = Rflush; send9pmsg(m); continue; } msgincref(m->oldm); break; case Tattach: m->afid = nil; if(m->tx.afid != NOFID && (m->afid = gethash(c->fid, m->tx.afid)) == nil){ err(m, "unknown fid"); continue; } if(m->afid) m->afid->ref++; m->fid = fidnew(m->tx.fid); if(puthash(c->fid, m->tx.fid, m->fid) < 0){ err(m, "duplicate fid"); continue; } m->fid->ref++; if(attached && m->afid==nil){ if(m->tx.aname[0] && strcmp(xaname, m->tx.aname) != 0){ err(m, "invalid attach name"); continue; } m->tx.afid = xafid; m->tx.aname = xaname; m->tx.uname = getuser(); /* what srv.c used */ repack(&m->tx, &m->tpkt); } break; case Twalk: if((m->fid = gethash(c->fid, m->tx.fid)) == nil){ err(m, "unknown fid"); continue; } m->fid->ref++; 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(attached){ err(m, "authentication not required"); continue; } if(noauth){ err(m, "authentication rejected"); continue; } m->afid = fidnew(m->tx.afid); if(puthash(c->fid, m->tx.afid, m->afid) < 0){ err(m, "duplicate fid"); continue; } m->afid->ref++; break; case Tcreate: if(m->tx.perm&(DMSYMLINK|DMDEVICE|DMNAMEDPIPE|DMSOCKET)){ err(m, "unsupported file type"); continue; } goto caseTopen; case Topenfd: if(m->tx.mode&~(OTRUNC|3)){ err(m, "bad openfd mode"); continue; } m->isopenfd = 1; m->tx.type = Topen; m->tpkt[4] = Topen; /* fall through */ caseTopen: case Topen: case Tclunk: case Tread: case Twrite: case Tremove: 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; /* reference passes to outq */ sendq(outq, m); while(c->nmsg >= MAXMSG){ c->inputstalled = 1; recvp(c->inc); } } if(verbose) fprint(2, "%T fd#%d eof; flushing conn\n", c->fd); /* flush all outstanding messages */ for(i=0; i<NHASH; i++){ while((h = c->tag[i]) != nil){ om = h->v; msgincref(om); /* for us */ m = msgnew(0); m->internal = 1; m->c = c; c->nmsg++; m->tx.type = Tflush; m->tx.tag = m->tag; m->tx.oldtag = om->tag; m->oldm = om; msgincref(om); msgincref(m); /* for outq */ sendomsg(m); mm = recvp(c->internal); assert(mm == m); msgput(m); /* got from recvp */ msgput(m); /* got from msgnew */ if(delhash(c->tag, om->ctag, om) == 0) msgput(om); /* got from hash table */ msgput(om); /* got from msgincref */ } } /* * outputthread has written all its messages * to the remote connection (because we've gotten all the replies!), * but it might not have gotten a chance to msgput * the very last one. sync up to make sure. */ memset(&sync, 0, sizeof sync); sync.sync = 1; sync.c = c; sendq(outq, &sync); recvp(c->outqdead); /* everything is quiet; can close the local output queue. */ sendq(c->outq, nil); recvp(c->outqdead); /* should be no messages left anywhere. */ assert(c->nmsg == 0); /* clunk all outstanding fids */ for(i=0; i<NHASH; i++){ for(h=c->fid[i]; h; h=hnext){ f = h->v; m = msgnew(0); m->internal = 1; m->c = c; c->nmsg++; m->tx.type = Tclunk; m->tx.tag = m->tag; m->tx.fid = f->fid; m->fid = f; f->ref++; msgincref(m); sendomsg(m); mm = recvp(c->internal); assert(mm == m); msgclear(m); msgput(m); /* got from recvp */ msgput(m); /* got from msgnew */ fidput(f); /* got from hash table */ hnext = h->next; free(h); } } out: closeioproc(io); assert(c->nmsg == 0); assert(c->nfid == 0); close(c->fd); chanfree(c->internal); c->internal = 0; chanfree(c->inc); c->inc = 0; free(c->inq); c->inq = 0; free(c); }