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");
73 /* wait for the muxer to give us our packet */
76 while(z->muxer && !r->done)
81 /* if not done, there's no muxer: start muxing */
88 if((p = vtrecv(z)) == nil){
89 werrstr("unexpected eof on venti connection");
98 /* if there is anyone else sleeping, wake first unfinished to mux */
100 for(i=0; i<256; i++){
102 if(rr && rr->sleeping && !rr->done){
117 vtrpc(VtConn *z, Packet *p)
119 return _vtrpc(z, p, nil);
123 gettag(VtConn *z, Rwait *r)
128 while(z->ntag == 256)
136 fprint(2, "libventi: ntag botch\n");
141 puttag(VtConn *z, Rwait *r, int tag)
143 assert(z->wait[tag] == r);
146 rwakeup(&z->tagrend);
150 muxrpc(VtConn *z, Packet *p)
152 uchar tag, buf[2], *top;
155 if((top = packetpeek(p, buf, 0, 2)) == nil){
156 fprint(2, "libventi: short packet in vtrpc\n");
162 if((r = z->wait[tag]) == nil){
163 fprint(2, "libventi: unexpected packet tag %d in vtrpc\n", tag);