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;
40 /* must malloc because stack could be private */
41 r = vtmallocz(sizeof(Rwait));
47 /* vtfcallrpc can't print packet because it doesn't have tag */
50 fprint(2, "%s -> %F\n", argv0, tx);
53 /* slam tag into packet */
54 top = packetpeek(p, buf, 0, 2);
60 werrstr("first two bytes must be in same packet fragment");
70 /* wait for the muxer to give us our packet */
73 while(z->muxer && !r->done)
78 /* if not done, there's no muxer: start muxing */
85 if((p = vtrecv(z)) == nil){
86 werrstr("unexpected eof on venti connection");
94 /* if there is anyone else sleeping, wake first unfinished to mux */
98 if(rr && rr->sleeping && !rr->done){
113 vtrpc(VtConn *z, Packet *p)
115 return _vtrpc(z, p, nil);
119 gettag(VtConn *z, Rwait *r)
124 while(z->ntag == 256)
132 fprint(2, "libventi: ntag botch\n");
137 puttag(VtConn *z, Rwait *r, int tag)
139 assert(z->wait[tag] == r);
142 rwakeup(&z->tagrend);
146 muxrpc(VtConn *z, Packet *p)
148 uchar tag, buf[2], *top;
151 if((top = packetpeek(p, buf, 0, 2)) == nil){
152 fprint(2, "libventi: short packet in vtrpc\n");
158 if((r = z->wait[tag]) == nil){
159 fprint(2, "libventi: unexpected packet tag %d in vtrpc\n", tag);