Beispiel #1
0
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);
	}	
}
Beispiel #2
0
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;
}
Beispiel #3
0
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();
}
Beispiel #4
0
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);
}
Beispiel #5
0
Datei: fdbuf.c Projekt: bazil/tra
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;
}
Beispiel #6
0
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);
}	
Beispiel #7
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);
}
Beispiel #8
0
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);
}			
Beispiel #9
0
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);
}