Blob


1 #include "std.h"
2 #include "dat.h"
4 Conv *conv;
6 ulong taggen = 1;
8 Conv*
9 convalloc(char *sysuser)
10 {
11 Conv *c;
13 c = mallocz(sizeof(Conv), 1);
14 if(c == nil)
15 return nil;
16 c->ref = 1;
17 c->tag = taggen++;
18 c->next = conv;
19 c->sysuser = estrdup(sysuser);
20 c->state = "nascent";
21 c->rpcwait = chancreate(sizeof(void*), 0);
22 c->keywait = chancreate(sizeof(void*), 0);
23 strcpy(c->err, "protocol has not started");
24 conv = c;
25 convreset(c);
26 return c;
27 }
29 void
30 convreset(Conv *c)
31 {
32 if(c->ref != 1){
33 c->hangup = 1;
34 nbsendp(c->rpcwait, 0);
35 while(c->ref > 1)
36 yield();
37 c->hangup = 0;
38 }
39 c->state = "nascent";
40 c->err[0] = '\0';
41 freeattr(c->attr);
42 c->attr = nil;
43 c->proto = nil;
44 c->rpc.op = 0;
45 c->active = 0;
46 c->done = 0;
47 c->hangup = 0;
48 }
50 void
51 convhangup(Conv *c)
52 {
53 c->hangup = 1;
54 c->rpc.op = 0;
55 (*c->kickreply)(c);
56 nbsendp(c->rpcwait, 0);
57 }
59 void
60 convclose(Conv *c)
61 {
62 Conv *p;
64 if(c == nil)
65 return;
67 if(--c->ref > 0)
68 return;
70 if(c == conv){
71 conv = c->next;
72 goto free;
73 }
74 for(p=conv; p && p->next!=c; p=p->next)
75 ;
76 if(p == nil){
77 print("cannot find conv in list\n");
78 return;
79 }
80 p->next = c->next;
82 free:
83 c->next = nil;
84 free(c);
85 }
87 static Rpc*
88 convgetrpc(Conv *c, int want)
89 {
90 for(;;){
91 if(c->hangup){
92 werrstr("hangup");
93 return nil;
94 }
95 if(c->rpc.op == RpcUnknown){
96 recvp(c->rpcwait);
97 if(c->hangup){
98 werrstr("hangup");
99 return nil;
101 if(c->rpc.op == RpcUnknown)
102 continue;
104 if(want < 0 || c->rpc.op == want)
105 return &c->rpc;
106 rpcrespond(c, "phase in state '%s' want '%s'", c->state, rpcname[want]);
108 /* not reached */
111 /* read until the done function tells us that's enough */
112 int
113 convreadfn(Conv *c, int (*done)(void*, int), char **ps)
115 int n;
116 Rpc *r;
117 char *s;
119 for(;;){
120 r = convgetrpc(c, RpcWrite);
121 if(r == nil)
122 return -1;
123 n = (*done)(r->data, r->count);
124 if(n == r->count)
125 break;
126 rpcrespond(c, "toosmall %d", n);
129 s = emalloc(r->count+1);
130 memmove(s, r->data, r->count);
131 s[r->count] = 0;
132 *ps = s;
133 rpcrespond(c, "ok");
134 return r->count;
137 /*
138 * read until we get a non-zero write. assumes remote side
139 * knows something about the protocol (is not auth_proxy).
140 * the remote side typically won't bother with the zero-length
141 * write to find out the length -- the loop is there only so the
142 * test program can call auth_proxy on both sides of a pipe
143 * to play a conversation.
144 */
145 int
146 convreadm(Conv *c, char **ps)
148 char *s;
149 Rpc *r;
151 for(;;){
152 r = convgetrpc(c, RpcWrite);
153 if(r == nil)
154 return -1;
155 if(r->count > 0)
156 break;
157 rpcrespond(c, "toosmall %d", AuthRpcMax);
159 s = emalloc(r->count+1);
160 memmove(s, r->data, r->count);
161 s[r->count] = 0;
162 *ps = s;
163 rpcrespond(c, "ok");
164 return r->count;
167 /* read exactly count bytes */
168 int
169 convread(Conv *c, void *data, int count)
171 Rpc *r;
173 for(;;){
174 r = convgetrpc(c, RpcWrite);
175 if(r == nil)
176 return -1;
177 if(r->count == count)
178 break;
179 if(r->count < count)
180 rpcrespond(c, "toosmall %d", count);
181 else
182 rpcrespond(c, "error too much data; want %d got %d", count, r->count);
184 memmove(data, r->data, count);
185 rpcrespond(c, "ok");
186 return 0;
189 /* write exactly count bytes */
190 int
191 convwrite(Conv *c, void *data, int count)
193 Rpc *r;
195 r = convgetrpc(c, RpcRead);
196 if(r == nil)
197 return -1;
198 rpcrespondn(c, "ok", data, count);
199 return 0;
202 /* print to the conversation */
203 int
204 convprint(Conv *c, char *fmt, ...)
206 char *s;
207 va_list arg;
208 int ret;
210 va_start(arg, fmt);
211 s = vsmprint(fmt, arg);
212 va_end(arg);
213 if(s == nil)
214 return -1;
215 ret = convwrite(c, s, strlen(s));
216 free(s);
217 return ret;
220 /* ask for a key */
221 int
222 convneedkey(Conv *c, Attr *a)
224 /*
225 * Piggyback key requests in the usual RPC channel.
226 * Wait for the next RPC and then send a key request
227 * in response. The keys get added out-of-band (via the
228 * ctl file), so assume the key has been added when the
229 * next request comes in.
230 */
231 if(convgetrpc(c, -1) == nil)
232 return -1;
233 rpcrespond(c, "needkey %A", a);
234 if(convgetrpc(c, -1) == nil)
235 return -1;
236 return 0;
239 /* ask for a replacement for a bad key*/
240 int
241 convbadkey(Conv *c, Key *k, char *msg, Attr *a)
243 if(convgetrpc(c, -1) == nil)
244 return -1;
245 rpcrespond(c, "badkey %A %N\n%s\n%A",
246 k->attr, k->privattr, msg, a);
247 if(convgetrpc(c, -1) == nil)
248 return -1;
249 return 0;