| ---
tconv.c (5286B)
---
1 #include "std.h"
2 #include "dat.h"
3
4 Conv *conv;
5
6 ulong taggen = 1;
7
8 Conv*
9 convalloc(char *sysuser)
10 {
11 Conv *c;
12
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 }
28
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 }
49
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 }
58
59 void
60 convclose(Conv *c)
61 {
62 Conv *p;
63
64 if(c == nil)
65 return;
66
67 if(--c->ref > 0)
68 return;
69
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;
81
82 free:
83 c->next = nil;
84 free(c);
85 }
86
87 static Rpc*
88 convgetrpc(Conv *c, int want)
89 {
90 for(;;){
91 if(c->hangup){
92 flog("convgetrpc: hangup");
93 werrstr("hangup");
94 return nil;
95 }
96 if(c->rpc.op == RpcUnknown){
97 recvp(c->rpcwait);
98 if(c->hangup){
99 flog("convgetrpc: hangup");
100 werrstr("hangup");
101 return nil;
102 }
103 if(c->rpc.op == RpcUnknown)
104 continue;
105 }
106 if(want < 0 || c->rpc.op == want)
107 return &c->rpc;
108 rpcrespond(c, "phase in state '%s' want '%s'", c->state, rpcname[want]);
109 }
110 /* not reached */
111 }
112
113 /* read until the done function tells us that's enough */
114 int
115 convreadfn(Conv *c, int (*done)(void*, int), char **ps)
116 {
117 int n;
118 Rpc *r;
119 char *s;
120
121 for(;;){
122 r = convgetrpc(c, RpcWrite);
123 if(r == nil)
124 return -1;
125 n = (*done)(r->data, r->count);
126 if(n == r->count)
127 break;
128 rpcrespond(c, "toosmall %d", n);
129 }
130
131 s = emalloc(r->count+1);
132 memmove(s, r->data, r->count);
133 s[r->count] = 0;
134 *ps = s;
135 rpcrespond(c, "ok");
136 return r->count;
137 }
138
139 /*
140 * read until we get a non-zero write. assumes remote side
141 * knows something about the protocol (is not auth_proxy).
142 * the remote side typically won't bother with the zero-length
143 * write to find out the length -- the loop is there only so the
144 * test program can call auth_proxy on both sides of a pipe
145 * to play a conversation.
146 */
147 int
148 convreadm(Conv *c, char **ps)
149 {
150 char *s;
151 Rpc *r;
152
153 for(;;){
154 r = convgetrpc(c, RpcWrite);
155 if(r == nil)
156 return -1;
157 if(r->count > 0)
158 break;
159 rpcrespond(c, "toosmall %d", AuthRpcMax);
160 }
161 s = emalloc(r->count+1);
162 memmove(s, r->data, r->count);
163 s[r->count] = 0;
164 *ps = s;
165 rpcrespond(c, "ok");
166 return r->count;
167 }
168
169 /* read exactly count bytes */
170 int
171 convread(Conv *c, void *data, int count)
172 {
173 Rpc *r;
174
175 for(;;){
176 r = convgetrpc(c, RpcWrite);
177 if(r == nil)
178 return -1;
179 if(r->count == count)
180 break;
181 if(r->count < count)
182 rpcrespond(c, "toosmall %d", count);
183 else
184 rpcrespond(c, "error too much data; want %d got %d", count, r->count);
185 }
186 memmove(data, r->data, count);
187 rpcrespond(c, "ok");
188 return 0;
189 }
190
191 /* write exactly count bytes */
192 int
193 convwrite(Conv *c, void *data, int count)
194 {
195 Rpc *r;
196
197 r = convgetrpc(c, RpcRead);
198 if(r == nil)
199 return -1;
200 rpcrespondn(c, "ok", data, count);
201 return 0;
202 }
203
204 /* print to the conversation */
205 int
206 convprint(Conv *c, char *fmt, ...)
207 {
208 char *s;
209 va_list arg;
210 int ret;
211
212 va_start(arg, fmt);
213 s = vsmprint(fmt, arg);
214 va_end(arg);
215 if(s == nil)
216 return -1;
217 ret = convwrite(c, s, strlen(s));
218 free(s);
219 return ret;
220 }
221
222 /* ask for a key */
223 int
224 convneedkey(Conv *c, Attr *a)
225 {
226 /*
227 * Piggyback key requests in the usual RPC channel.
228 * Wait for the next RPC and then send a key request
229 * in response. The keys get added out-of-band (via the
230 * ctl file), so assume the key has been added when the
231 * next request comes in.
232 *
233 * The convgetrpc seems dodgy, because we might be in
234 * the middle of an rpc, and what about the one that comes
235 * in later? It's all actually okay: convgetrpc is idempotent
236 * until rpcrespond is called, so if we're in the middle of an rpc,
237 * the first convgetrpc is a no-op, the rpcrespond sends back
238 * the needkey, and then the client repeats the rpc we're in
239 * the middle of. Otherwise, if we're not in the middle of an
240 * rpc, the first convgetrpc waits for one, we respond needkey,
241 * and then the second convgetrpc waits for another. Because
242 * there is no second response, eventually the caller will get
243 * around to asking for an rpc itself, at which point the already
244 * gotten rpc will be returned again.
245 */
246 if(convgetrpc(c, -1) == nil)
247 return -1;
248 if(conv->proto)
249 a = addattrs(parseattr(c->proto->keyprompt), a);
250 flog("convneedkey %A", a);
251 rpcrespond(c, "needkey %A", a);
252 if(convgetrpc(c, -1) == nil)
253 return -1;
254 flog("convneedkey returning");
255 return 0;
256 }
257
258 /* ask for a replacement for a bad key*/
259 int
260 convbadkey(Conv *c, Key *k, char *msg, Attr *a)
261 {
262 if(convgetrpc(c, -1) == nil)
263 return -1;
264 flog("convbadkey %A %N / %s / %A", k->attr, k->privattr, msg, a);
265 rpcrespond(c, "badkey %A %N\n%s\n%A",
266 k->attr, k->privattr, msg, a);
267 if(convgetrpc(c, -1) == nil)
268 return -1;
269 return 0;
270 } |