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