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;
41 werrstr("not connected");
46 /* must malloc because stack could be private */
47 r = vtmallocz(sizeof(Rwait));
53 /* vtfcallrpc can't print packet because it doesn't have tag */
56 fprint(2, "%s -> %F\n", argv0, tx);
59 /* slam tag into packet */
60 top = packetpeek(p, buf, 0, 2);
66 werrstr("first two bytes must be in same packet fragment");
79 /* wait for the muxer to give us our packet */
82 while(z->muxer && !r->done)
87 /* if not done, there's no muxer: start muxing */
94 if((p = vtrecv(z)) == nil){
95 werrstr("unexpected eof on venti connection");
104 /* if there is anyone else sleeping, wake first unfinished to mux */
106 for(i=0; i<256; i++){
108 if(rr && rr->sleeping && !rr->done){
123 vtrpc(VtConn *z, Packet *p)
125 return _vtrpc(z, p, nil);
129 gettag(VtConn *z, Rwait *r)
134 while(z->ntag == 256)
142 fprint(2, "libventi: ntag botch\n");
147 puttag(VtConn *z, Rwait *r, int tag)
149 assert(z->wait[tag] == r);
152 rwakeup(&z->tagrend);
156 muxrpc(VtConn *z, Packet *p)
158 uchar tag, buf[2], *top;
161 if((top = packetpeek(p, buf, 0, 2)) == nil){
162 fprint(2, "libventi: short packet in vtrpc\n");
168 if((r = z->wait[tag]) == nil){
169 fprint(2, "libventi: unexpected packet tag %d in vtrpc\n", tag);