19a747e4fSDavid du Colombier /*
29a747e4fSDavid du Colombier * p9any - protocol negotiator.
39a747e4fSDavid du Colombier *
49a747e4fSDavid du Colombier * Protocol:
59a747e4fSDavid du Colombier * Server->Client: list of proto@domain, tokenize separated, nul terminated
69a747e4fSDavid du Colombier * Client->Server: proto domain, tokenize separated (not proto@domain), nul terminated
79a747e4fSDavid du Colombier *
89a747e4fSDavid du Colombier * Server protocol:
99a747e4fSDavid du Colombier * read list of protocols.
109a747e4fSDavid du Colombier * write null-terminated
119a747e4fSDavid du Colombier */
129a747e4fSDavid du Colombier
139a747e4fSDavid du Colombier #include "dat.h"
149a747e4fSDavid du Colombier
159a747e4fSDavid du Colombier static Proto *negotiable[] = {
169a747e4fSDavid du Colombier &p9sk1,
179a747e4fSDavid du Colombier };
189a747e4fSDavid du Colombier
199a747e4fSDavid du Colombier struct State
209a747e4fSDavid du Colombier {
219a747e4fSDavid du Colombier Fsstate subfss;
229a747e4fSDavid du Colombier State *substate; /* be very careful; this is not one of our States */
239a747e4fSDavid du Colombier Proto *subproto;
249a747e4fSDavid du Colombier int keyasked;
259a747e4fSDavid du Colombier String *subdom;
269a747e4fSDavid du Colombier int version;
279a747e4fSDavid du Colombier };
289a747e4fSDavid du Colombier
299a747e4fSDavid du Colombier enum
309a747e4fSDavid du Colombier {
319a747e4fSDavid du Colombier CNeedProtos,
329a747e4fSDavid du Colombier CHaveProto,
339a747e4fSDavid du Colombier CNeedOK,
349a747e4fSDavid du Colombier CRelay,
359a747e4fSDavid du Colombier
369a747e4fSDavid du Colombier SHaveProtos,
379a747e4fSDavid du Colombier SNeedProto,
389a747e4fSDavid du Colombier SHaveOK,
399a747e4fSDavid du Colombier SRelay,
409a747e4fSDavid du Colombier
419a747e4fSDavid du Colombier Maxphase,
429a747e4fSDavid du Colombier };
439a747e4fSDavid du Colombier
449a747e4fSDavid du Colombier static char *phasenames[Maxphase] =
459a747e4fSDavid du Colombier {
469a747e4fSDavid du Colombier [CNeedProtos] "CNeedProtos",
479a747e4fSDavid du Colombier [CHaveProto] "CHaveProto",
489a747e4fSDavid du Colombier [CNeedOK] "CNeedOK",
499a747e4fSDavid du Colombier [CRelay] "CRelay",
509a747e4fSDavid du Colombier [SHaveProtos] "SHaveProtos",
519a747e4fSDavid du Colombier [SNeedProto] "SNeedProto",
529a747e4fSDavid du Colombier [SHaveOK] "SHaveOK",
539a747e4fSDavid du Colombier [SRelay] "SRelay",
549a747e4fSDavid du Colombier };
559a747e4fSDavid du Colombier
569a747e4fSDavid du Colombier static int
p9anyinit(Proto *,Fsstate * fss)579a747e4fSDavid du Colombier p9anyinit(Proto*, Fsstate *fss)
589a747e4fSDavid du Colombier {
599a747e4fSDavid du Colombier int iscli;
609a747e4fSDavid du Colombier State *s;
619a747e4fSDavid du Colombier
622ebbfa15SDavid du Colombier if((iscli = isclient(_strfindattr(fss->attr, "role"))) < 0)
639a747e4fSDavid du Colombier return failure(fss, nil);
649a747e4fSDavid du Colombier
659a747e4fSDavid du Colombier s = emalloc(sizeof *s);
669a747e4fSDavid du Colombier fss = fss;
679a747e4fSDavid du Colombier fss->phasename = phasenames;
689a747e4fSDavid du Colombier fss->maxphase = Maxphase;
699a747e4fSDavid du Colombier if(iscli)
709a747e4fSDavid du Colombier fss->phase = CNeedProtos;
719a747e4fSDavid du Colombier else
729a747e4fSDavid du Colombier fss->phase = SHaveProtos;
739a747e4fSDavid du Colombier s->version = 1;
749a747e4fSDavid du Colombier fss->ps = s;
759a747e4fSDavid du Colombier return RpcOk;
769a747e4fSDavid du Colombier }
779a747e4fSDavid du Colombier
789a747e4fSDavid du Colombier static void
p9anyclose(Fsstate * fss)799a747e4fSDavid du Colombier p9anyclose(Fsstate *fss)
809a747e4fSDavid du Colombier {
819a747e4fSDavid du Colombier State *s;
829a747e4fSDavid du Colombier
839a747e4fSDavid du Colombier s = fss->ps;
849a747e4fSDavid du Colombier if(s->subproto && s->subfss.ps && s->subproto->close)
859a747e4fSDavid du Colombier (*s->subproto->close)(&s->subfss);
869a747e4fSDavid du Colombier s->subproto = nil;
879a747e4fSDavid du Colombier s->substate = nil;
889a747e4fSDavid du Colombier s_free(s->subdom);
899a747e4fSDavid du Colombier s->subdom = nil;
909a747e4fSDavid du Colombier s->keyasked = 0;
919a747e4fSDavid du Colombier memset(&s->subfss, 0, sizeof s->subfss);
929a747e4fSDavid du Colombier free(s);
939a747e4fSDavid du Colombier }
949a747e4fSDavid du Colombier
959a747e4fSDavid du Colombier static void
setupfss(Fsstate * fss,State * s,Key * k)969a747e4fSDavid du Colombier setupfss(Fsstate *fss, State *s, Key *k)
979a747e4fSDavid du Colombier {
989a747e4fSDavid du Colombier fss->attr = setattr(fss->attr, "proto=%q", s->subproto->name);
992ebbfa15SDavid du Colombier fss->attr = setattr(fss->attr, "dom=%q", _strfindattr(k->attr, "dom"));
1009a747e4fSDavid du Colombier s->subfss.attr = fss->attr;
1019a747e4fSDavid du Colombier s->subfss.phase = Notstarted;
1029a747e4fSDavid du Colombier s->subfss.sysuser = fss->sysuser;
1039a747e4fSDavid du Colombier s->subfss.seqnum = fss->seqnum;
1049a747e4fSDavid du Colombier s->subfss.conf = fss->conf;
1059a747e4fSDavid du Colombier s->subfss.nconf = fss->nconf;
1069a747e4fSDavid du Colombier }
1079a747e4fSDavid du Colombier
1089a747e4fSDavid du Colombier static int
passret(Fsstate * fss,State * s,int ret)1099a747e4fSDavid du Colombier passret(Fsstate *fss, State *s, int ret)
1109a747e4fSDavid du Colombier {
1119a747e4fSDavid du Colombier switch(ret){
1129a747e4fSDavid du Colombier default:
1139a747e4fSDavid du Colombier return ret;
1149a747e4fSDavid du Colombier case RpcFailure:
1159a747e4fSDavid du Colombier if(s->subfss.phase == Broken)
1169a747e4fSDavid du Colombier fss->phase = Broken;
1179a747e4fSDavid du Colombier memmove(fss->err, s->subfss.err, sizeof fss->err);
1189a747e4fSDavid du Colombier return ret;
1199a747e4fSDavid du Colombier case RpcNeedkey:
1209a747e4fSDavid du Colombier memmove(fss->keyinfo, s->subfss.keyinfo, sizeof fss->keyinfo);
1219a747e4fSDavid du Colombier return ret;
1229a747e4fSDavid du Colombier case RpcOk:
1239a747e4fSDavid du Colombier if(s->subfss.haveai){
1249a747e4fSDavid du Colombier fss->haveai = 1;
1259a747e4fSDavid du Colombier fss->ai = s->subfss.ai;
1269a747e4fSDavid du Colombier s->subfss.haveai = 0;
1279a747e4fSDavid du Colombier }
1289a747e4fSDavid du Colombier if(s->subfss.phase == Established)
1299a747e4fSDavid du Colombier fss->phase = Established;
1309a747e4fSDavid du Colombier return ret;
1319a747e4fSDavid du Colombier case RpcToosmall:
1329a747e4fSDavid du Colombier fss->rpc.nwant = s->subfss.rpc.nwant;
1339a747e4fSDavid du Colombier return ret;
1349a747e4fSDavid du Colombier case RpcConfirm:
1359a747e4fSDavid du Colombier fss->conf = s->subfss.conf;
1369a747e4fSDavid du Colombier fss->nconf = s->subfss.nconf;
1379a747e4fSDavid du Colombier return ret;
1389a747e4fSDavid du Colombier }
1399a747e4fSDavid du Colombier }
1409a747e4fSDavid du Colombier
1419a747e4fSDavid du Colombier static int
p9anyread(Fsstate * fss,void * a,uint * n)1429a747e4fSDavid du Colombier p9anyread(Fsstate *fss, void *a, uint *n)
1439a747e4fSDavid du Colombier {
144*260f7b65SDavid du Colombier int i, m, ophase, ret;
1459a747e4fSDavid du Colombier Attr *anew;
1469a747e4fSDavid du Colombier Key *k;
147*260f7b65SDavid du Colombier Keyinfo ki;
1489a747e4fSDavid du Colombier String *negstr;
1499a747e4fSDavid du Colombier State *s;
1509a747e4fSDavid du Colombier
1519a747e4fSDavid du Colombier s = fss->ps;
1529a747e4fSDavid du Colombier switch(fss->phase){
1539a747e4fSDavid du Colombier default:
1549a747e4fSDavid du Colombier return phaseerror(fss, "read");
1559a747e4fSDavid du Colombier
1569a747e4fSDavid du Colombier case SHaveProtos:
1579a747e4fSDavid du Colombier m = 0;
1589a747e4fSDavid du Colombier negstr = s_new();
159*260f7b65SDavid du Colombier mkkeyinfo(&ki, fss, nil);
160*260f7b65SDavid du Colombier ki.attr = nil;
161*260f7b65SDavid du Colombier ki.noconf = 1;
162*260f7b65SDavid du Colombier ki.user = nil;
1639a747e4fSDavid du Colombier for(i=0; i<nelem(negotiable); i++){
1649a747e4fSDavid du Colombier anew = setattr(_copyattr(fss->attr), "proto=%q dom?", negotiable[i]->name);
165*260f7b65SDavid du Colombier ki.attr = anew;
166*260f7b65SDavid du Colombier for(ki.skip=0; findkey(&k, &ki, nil)==RpcOk; ki.skip++){
1679a747e4fSDavid du Colombier if(m++)
1689a747e4fSDavid du Colombier s_append(negstr, " ");
1699a747e4fSDavid du Colombier s_append(negstr, negotiable[i]->name);
1709a747e4fSDavid du Colombier s_append(negstr, "@");
1712ebbfa15SDavid du Colombier s_append(negstr, _strfindattr(k->attr, "dom"));
1729a747e4fSDavid du Colombier closekey(k);
1739a747e4fSDavid du Colombier }
1749a747e4fSDavid du Colombier _freeattr(anew);
1759a747e4fSDavid du Colombier }
1769a747e4fSDavid du Colombier if(m == 0){
1779a747e4fSDavid du Colombier s_free(negstr);
1789a747e4fSDavid du Colombier return failure(fss, Enegotiation);
1799a747e4fSDavid du Colombier }
1809a747e4fSDavid du Colombier i = s_len(negstr)+1;
1819a747e4fSDavid du Colombier if(*n < i){
1829a747e4fSDavid du Colombier s_free(negstr);
1839a747e4fSDavid du Colombier return toosmall(fss, i);
1849a747e4fSDavid du Colombier }
1859a747e4fSDavid du Colombier *n = i;
1869a747e4fSDavid du Colombier memmove(a, s_to_c(negstr), i+1);
1879a747e4fSDavid du Colombier fss->phase = SNeedProto;
1889a747e4fSDavid du Colombier s_free(negstr);
1899a747e4fSDavid du Colombier return RpcOk;
1909a747e4fSDavid du Colombier
1919a747e4fSDavid du Colombier case CHaveProto:
1929a747e4fSDavid du Colombier i = strlen(s->subproto->name)+1+s_len(s->subdom)+1;
1939a747e4fSDavid du Colombier if(*n < i)
1949a747e4fSDavid du Colombier return toosmall(fss, i);
1959a747e4fSDavid du Colombier *n = i;
1969a747e4fSDavid du Colombier strcpy(a, s->subproto->name);
1979a747e4fSDavid du Colombier strcat(a, " ");
1989a747e4fSDavid du Colombier strcat(a, s_to_c(s->subdom));
1999a747e4fSDavid du Colombier if(s->version == 1)
2009a747e4fSDavid du Colombier fss->phase = CRelay;
2019a747e4fSDavid du Colombier else
2029a747e4fSDavid du Colombier fss->phase = CNeedOK;
2039a747e4fSDavid du Colombier return RpcOk;
2049a747e4fSDavid du Colombier
2059a747e4fSDavid du Colombier case SHaveOK:
2069a747e4fSDavid du Colombier i = 3;
2079a747e4fSDavid du Colombier if(*n < i)
2089a747e4fSDavid du Colombier return toosmall(fss, i);
2099a747e4fSDavid du Colombier *n = i;
2109a747e4fSDavid du Colombier strcpy(a, "OK");
2119a747e4fSDavid du Colombier fss->phase = SRelay;
2129a747e4fSDavid du Colombier return RpcOk;
2139a747e4fSDavid du Colombier
2149a747e4fSDavid du Colombier case CRelay:
2159a747e4fSDavid du Colombier case SRelay:
2169a747e4fSDavid du Colombier ophase = s->subfss.phase;
2179a747e4fSDavid du Colombier ret = (*s->subproto->read)(&s->subfss, a, n);
2189a747e4fSDavid du Colombier rpcrdwrlog(&s->subfss, "read", *n, ophase, ret);
2199a747e4fSDavid du Colombier return passret(fss, s, ret);
2209a747e4fSDavid du Colombier }
2219a747e4fSDavid du Colombier }
2229a747e4fSDavid du Colombier
2239a747e4fSDavid du Colombier static char*
getdom(char * p)2249a747e4fSDavid du Colombier getdom(char *p)
2259a747e4fSDavid du Colombier {
2269a747e4fSDavid du Colombier p = strchr(p, '@');
2279a747e4fSDavid du Colombier if(p == nil)
2289a747e4fSDavid du Colombier return "";
2299a747e4fSDavid du Colombier return p+1;
2309a747e4fSDavid du Colombier }
2319a747e4fSDavid du Colombier
2329a747e4fSDavid du Colombier static Proto*
findneg(char * name)2339a747e4fSDavid du Colombier findneg(char *name)
2349a747e4fSDavid du Colombier {
2359a747e4fSDavid du Colombier int i, len;
2369a747e4fSDavid du Colombier char *p;
2379a747e4fSDavid du Colombier
2389a747e4fSDavid du Colombier if(p = strchr(name, '@'))
2399a747e4fSDavid du Colombier len = p-name;
2409a747e4fSDavid du Colombier else
2419a747e4fSDavid du Colombier len = strlen(name);
2429a747e4fSDavid du Colombier
2439a747e4fSDavid du Colombier for(i=0; i<nelem(negotiable); i++)
2449a747e4fSDavid du Colombier if(strncmp(negotiable[i]->name, name, len) == 0 && negotiable[i]->name[len] == 0)
2459a747e4fSDavid du Colombier return negotiable[i];
2469a747e4fSDavid du Colombier return nil;
2479a747e4fSDavid du Colombier }
2489a747e4fSDavid du Colombier
2499a747e4fSDavid du Colombier static int
p9anywrite(Fsstate * fss,void * va,uint n)2509a747e4fSDavid du Colombier p9anywrite(Fsstate *fss, void *va, uint n)
2519a747e4fSDavid du Colombier {
2529a747e4fSDavid du Colombier char *a, *dom, *user, *token[20];
2539a747e4fSDavid du Colombier int asking, i, m, ophase, ret;
2549a747e4fSDavid du Colombier Attr *anew, *anewsf, *attr;
2559a747e4fSDavid du Colombier Key *k;
256*260f7b65SDavid du Colombier Keyinfo ki;
2579a747e4fSDavid du Colombier Proto *p;
2589a747e4fSDavid du Colombier State *s;
2599a747e4fSDavid du Colombier
2609a747e4fSDavid du Colombier s = fss->ps;
2619a747e4fSDavid du Colombier a = va;
2629a747e4fSDavid du Colombier switch(fss->phase){
2639a747e4fSDavid du Colombier default:
2649a747e4fSDavid du Colombier return phaseerror(fss, "write");
2659a747e4fSDavid du Colombier
2669a747e4fSDavid du Colombier case CNeedProtos:
2679a747e4fSDavid du Colombier if(n==0 || a[n-1] != '\0')
2689a747e4fSDavid du Colombier return toosmall(fss, 2048);
2699a747e4fSDavid du Colombier a = estrdup(a);
2709a747e4fSDavid du Colombier m = tokenize(a, token, nelem(token));
2719a747e4fSDavid du Colombier if(m > 0 && strncmp(token[0], "v.", 2) == 0){
2729a747e4fSDavid du Colombier s->version = atoi(token[0]+2);
273d9306527SDavid du Colombier if(s->version != 2){
274d9306527SDavid du Colombier free(a);
2759a747e4fSDavid du Colombier return failure(fss, "unknown version of p9any");
2769a747e4fSDavid du Colombier }
277d9306527SDavid du Colombier }
2789a747e4fSDavid du Colombier
2799a747e4fSDavid du Colombier /*
2809a747e4fSDavid du Colombier * look for a key
2819a747e4fSDavid du Colombier */
2829a747e4fSDavid du Colombier anew = _delattr(_delattr(_copyattr(fss->attr), "proto"), "role");
2839a747e4fSDavid du Colombier anewsf = _delattr(_copyattr(anew), "user");
2842ebbfa15SDavid du Colombier user = _strfindattr(anew, "user");
2859a747e4fSDavid du Colombier k = nil;
2869a747e4fSDavid du Colombier p = nil;
2879a747e4fSDavid du Colombier dom = nil;
2889a747e4fSDavid du Colombier for(i=(s->version==1?0:1); i<m; i++){
2899a747e4fSDavid du Colombier p = findneg(token[i]);
2909a747e4fSDavid du Colombier if(p == nil)
2919a747e4fSDavid du Colombier continue;
2929a747e4fSDavid du Colombier dom = getdom(token[i]);
2939a747e4fSDavid du Colombier ret = RpcFailure;
294*260f7b65SDavid du Colombier mkkeyinfo(&ki, fss, nil);
295*260f7b65SDavid du Colombier if(user==nil || strcmp(user, fss->sysuser)==0){
296*260f7b65SDavid du Colombier ki.attr = anewsf;
297*260f7b65SDavid du Colombier ki.user = nil;
298*260f7b65SDavid du Colombier ret = findkey(&k, &ki, "proto=%q dom=%q role=speakfor %s",
2999a747e4fSDavid du Colombier p->name, dom, p->keyprompt);
300*260f7b65SDavid du Colombier }
301*260f7b65SDavid du Colombier if(ret == RpcFailure){
302*260f7b65SDavid du Colombier ki.attr = anew;
303*260f7b65SDavid du Colombier ki.user = fss->sysuser;
304*260f7b65SDavid du Colombier ret = findkey(&k, &ki,
3059a747e4fSDavid du Colombier "proto=%q dom=%q role=client %s",
3069a747e4fSDavid du Colombier p->name, dom, p->keyprompt);
307*260f7b65SDavid du Colombier }
308d9306527SDavid du Colombier if(ret == RpcConfirm){
309d9306527SDavid du Colombier free(a);
3109a747e4fSDavid du Colombier return ret;
311d9306527SDavid du Colombier }
3129a747e4fSDavid du Colombier if(ret == RpcOk)
3139a747e4fSDavid du Colombier break;
3149a747e4fSDavid du Colombier }
3159a747e4fSDavid du Colombier _freeattr(anewsf);
3169a747e4fSDavid du Colombier
3179a747e4fSDavid du Colombier /*
3189a747e4fSDavid du Colombier * no acceptable key, go through the proto@domains one at a time.
3199a747e4fSDavid du Colombier */
3209a747e4fSDavid du Colombier asking = 0;
3219a747e4fSDavid du Colombier if(k == nil){
3229a747e4fSDavid du Colombier while(!asking && s->keyasked < m){
3239a747e4fSDavid du Colombier p = findneg(token[s->keyasked]);
3249a747e4fSDavid du Colombier if(p == nil){
3259a747e4fSDavid du Colombier s->keyasked++;
3269a747e4fSDavid du Colombier continue;
3279a747e4fSDavid du Colombier }
3289a747e4fSDavid du Colombier dom = getdom(token[s->keyasked]);
329*260f7b65SDavid du Colombier mkkeyinfo(&ki, fss, nil);
330*260f7b65SDavid du Colombier ki.attr = anew;
331*260f7b65SDavid du Colombier ret = findkey(&k, &ki,
3329a747e4fSDavid du Colombier "proto=%q dom=%q role=client %s",
3339a747e4fSDavid du Colombier p->name, dom, p->keyprompt);
3349a747e4fSDavid du Colombier s->keyasked++;
3359a747e4fSDavid du Colombier if(ret == RpcNeedkey){
3369a747e4fSDavid du Colombier asking = 1;
3379a747e4fSDavid du Colombier break;
3389a747e4fSDavid du Colombier }
3399a747e4fSDavid du Colombier }
3409a747e4fSDavid du Colombier }
3419a747e4fSDavid du Colombier if(k == nil){
3429a747e4fSDavid du Colombier free(a);
3439a747e4fSDavid du Colombier _freeattr(anew);
3449a747e4fSDavid du Colombier if(asking)
3459a747e4fSDavid du Colombier return RpcNeedkey;
3469a747e4fSDavid du Colombier else if(s->keyasked)
3479a747e4fSDavid du Colombier return failure(fss, nil);
3489a747e4fSDavid du Colombier else
3499a747e4fSDavid du Colombier return failure(fss, Enegotiation);
3509a747e4fSDavid du Colombier }
3519a747e4fSDavid du Colombier s->subdom = s_copy(dom);
3529a747e4fSDavid du Colombier s->subproto = p;
3539a747e4fSDavid du Colombier free(a);
3549a747e4fSDavid du Colombier _freeattr(anew);
3559a747e4fSDavid du Colombier setupfss(fss, s, k);
3569a747e4fSDavid du Colombier closekey(k);
3579a747e4fSDavid du Colombier ret = (*s->subproto->init)(p, &s->subfss);
3589a747e4fSDavid du Colombier rpcstartlog(s->subfss.attr, &s->subfss, ret);
3599a747e4fSDavid du Colombier if(ret == RpcOk)
3609a747e4fSDavid du Colombier fss->phase = CHaveProto;
3619a747e4fSDavid du Colombier return passret(fss, s, ret);
3629a747e4fSDavid du Colombier
3639a747e4fSDavid du Colombier case SNeedProto:
3649a747e4fSDavid du Colombier if(n==0 || a[n-1] != '\0')
3659a747e4fSDavid du Colombier return toosmall(fss, n+1);
3669a747e4fSDavid du Colombier a = estrdup(a);
3679a747e4fSDavid du Colombier m = tokenize(a, token, nelem(token));
368d9306527SDavid du Colombier if(m != 2){
369d9306527SDavid du Colombier free(a);
3709a747e4fSDavid du Colombier return failure(fss, Ebadarg);
371d9306527SDavid du Colombier }
3729a747e4fSDavid du Colombier p = findneg(token[0]);
373d9306527SDavid du Colombier if(p == nil){
374d9306527SDavid du Colombier free(a);
3759a747e4fSDavid du Colombier return failure(fss, Enegotiation);
376d9306527SDavid du Colombier }
3779a747e4fSDavid du Colombier attr = _delattr(_copyattr(fss->attr), "proto");
378*260f7b65SDavid du Colombier mkkeyinfo(&ki, fss, nil);
379*260f7b65SDavid du Colombier ki.attr = attr;
380*260f7b65SDavid du Colombier ki.user = nil;
381*260f7b65SDavid du Colombier ret = findkey(&k, &ki, "proto=%q dom=%q role=server", token[0], token[1]);
382d9306527SDavid du Colombier free(a);
3839a747e4fSDavid du Colombier _freeattr(attr);
3849a747e4fSDavid du Colombier if(ret == RpcConfirm)
3859a747e4fSDavid du Colombier return ret;
3869a747e4fSDavid du Colombier if(ret != RpcOk)
3879a747e4fSDavid du Colombier return failure(fss, Enegotiation);
3889a747e4fSDavid du Colombier s->subproto = p;
3899a747e4fSDavid du Colombier setupfss(fss, s, k);
3909a747e4fSDavid du Colombier closekey(k);
3919a747e4fSDavid du Colombier ret = (*s->subproto->init)(p, &s->subfss);
3929a747e4fSDavid du Colombier if(ret == RpcOk){
3939a747e4fSDavid du Colombier if(s->version == 1)
3949a747e4fSDavid du Colombier fss->phase = SRelay;
3959a747e4fSDavid du Colombier else
3969a747e4fSDavid du Colombier fss->phase = SHaveOK;
3979a747e4fSDavid du Colombier }
3989a747e4fSDavid du Colombier return passret(fss, s, ret);
3999a747e4fSDavid du Colombier
4009a747e4fSDavid du Colombier case CNeedOK:
4019a747e4fSDavid du Colombier if(n < 3)
4029a747e4fSDavid du Colombier return toosmall(fss, 3);
4039a747e4fSDavid du Colombier if(strcmp("OK", a) != 0)
4049a747e4fSDavid du Colombier return failure(fss, "server gave up");
4059a747e4fSDavid du Colombier fss->phase = CRelay;
4069a747e4fSDavid du Colombier return RpcOk;
4079a747e4fSDavid du Colombier
4089a747e4fSDavid du Colombier case CRelay:
4099a747e4fSDavid du Colombier case SRelay:
4109a747e4fSDavid du Colombier ophase = s->subfss.phase;
4119a747e4fSDavid du Colombier ret = (*s->subproto->write)(&s->subfss, va, n);
4129a747e4fSDavid du Colombier rpcrdwrlog(&s->subfss, "write", n, ophase, ret);
4139a747e4fSDavid du Colombier return passret(fss, s, ret);
4149a747e4fSDavid du Colombier }
4159a747e4fSDavid du Colombier }
4169a747e4fSDavid du Colombier
4179a747e4fSDavid du Colombier Proto p9any =
4189a747e4fSDavid du Colombier {
4199a747e4fSDavid du Colombier .name= "p9any",
4209a747e4fSDavid du Colombier .init= p9anyinit,
4219a747e4fSDavid du Colombier .write= p9anywrite,
4229a747e4fSDavid du Colombier .read= p9anyread,
4239a747e4fSDavid du Colombier .close= p9anyclose,
4249a747e4fSDavid du Colombier };
425