conv.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 }