tconv.c - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       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 }