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*);
32 Packet *vtrpc(VtConn*, Packet*);
35 vtrpc(VtConn *z, Packet *p)
38 uchar tag, buf[2], *top;
41 /* must malloc because stack could be private */
42 r = vtmallocz(sizeof(Rwait));
48 /* slam tag into packet */
49 top = packetpeek(p, buf, 0, 2);
55 werrstr("first two bytes must be in same packet fragment");
65 /* wait for the muxer to give us our packet */
68 while(z->muxer && !r->done)
73 /* if not done, there's no muxer: start muxing */
80 if((p = vtrecv(z)) == nil){
81 werrstr("unexpected eof on venti connection");
89 /* if there is anyone else sleeping, wake them to mux */
92 if(z->wait[i] != nil && ((Rwait*)z->wait[i])->sleeping)
95 fprint(2, "libventi: nsleep botch\n");
97 rwakeup(&((Rwait*)z->wait[i])->r);
109 gettag(VtConn *z, Rwait *r)
114 while(z->ntag == 256)
122 fprint(2, "libventi: ntag botch\n");
127 puttag(VtConn *z, Rwait *r, int tag)
129 assert(z->wait[tag] == r);
132 rwakeup(&z->tagrend);
136 muxrpc(VtConn *z, Packet *p)
138 uchar tag, buf[2], *top;
141 if((top = packetpeek(p, buf, 0, 2)) == nil){
142 fprint(2, "libventi: short packet in vtrpc\n");
148 if((r = z->wait[tag]) == nil){
149 fprint(2, "libventi: unexpected packet tag %d in vtrpc\n", tag);