2 * Multiplexed Venti client. It would be nice if we
3 * could turn this into a generic library routine rather
4 * than keep it Venti specific. A user-level 9P client
5 * could use something like this too.
7 * (Actually it does - this should be replaced with libmux,
8 * which should be renamed librpcmux.)
10 * This is a little more complicated than it might be
11 * because we want it to work well within and without libthread.
13 * The mux code is inspired by tra's, which is inspired by the Plan 9 kernel.
20 typedef struct Rwait Rwait;
29 static int gettag(VtConn*, Rwait*);
30 static void puttag(VtConn*, Rwait*, int);
31 static void muxrpc(VtConn*, Packet*);
34 _vtrpc(VtConn *z, Packet *p, VtFcall *tx)
37 uchar tag, buf[2], *top;
42 werrstr("not connected");
47 /* must malloc because stack could be private */
48 r = vtmallocz(sizeof(Rwait));
54 /* vtfcallrpc can't print packet because it doesn't have tag */
57 fprint(2, "%s -> %F\n", argv0, tx);
60 /* slam tag into packet */
61 top = packetpeek(p, buf, 0, 2);
67 werrstr("first two bytes must be in same packet fragment");
80 /* wait for the muxer to give us our packet */
83 while(z->muxer && !r->done)
88 /* if not done, there's no muxer: start muxing */
95 if((p = vtrecv(z)) == nil){
96 werrstr("unexpected eof on venti connection");
105 /* if there is anyone else sleeping, wake first unfinished to mux */
107 for(i=0; i<256; i++){
109 if(rr && rr->sleeping && !rr->done){
124 vtrpc(VtConn *z, Packet *p)
126 return _vtrpc(z, p, nil);
130 gettag(VtConn *z, Rwait *r)
135 while(z->ntag == 256)
143 fprint(2, "libventi: ntag botch\n");
148 puttag(VtConn *z, Rwait *r, int tag)
150 assert(z->wait[tag] == r);
153 rwakeup(&z->tagrend);
157 muxrpc(VtConn *z, Packet *p)
159 uchar tag, buf[2], *top;
162 if((top = packetpeek(p, buf, 0, 2)) == nil){
163 fprint(2, "libventi: short packet in vtrpc\n");
169 if((r = z->wait[tag]) == nil){
170 fprint(2, "libventi: unexpected packet tag %d in vtrpc\n", tag);