p9any.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. /*
  10. * p9any - protocol negotiator.
  11. *
  12. * Protocol:
  13. * Server->Client: list of proto@domain, tokenize separated, nul terminated
  14. * Client->Server: proto domain, tokenize separated (not proto@domain), nul terminated
  15. *
  16. * Server protocol:
  17. * read list of protocols.
  18. * write null-terminated
  19. */
  20. #include "dat.h"
  21. static Proto *negotiable[] = {
  22. &p9sk1,
  23. };
  24. struct State
  25. {
  26. Fsstate subfss;
  27. State *substate; /* be very careful; this is not one of our States */
  28. Proto *subproto;
  29. int keyasked;
  30. String *subdom;
  31. int version;
  32. };
  33. enum
  34. {
  35. CNeedProtos,
  36. CHaveProto,
  37. CNeedOK,
  38. CRelay,
  39. SHaveProtos,
  40. SNeedProto,
  41. SHaveOK,
  42. SRelay,
  43. Maxphase,
  44. };
  45. static char *phasenames[Maxphase] =
  46. {
  47. [CNeedProtos] "CNeedProtos",
  48. [CHaveProto] "CHaveProto",
  49. [CNeedOK] "CNeedOK",
  50. [CRelay] "CRelay",
  51. [SHaveProtos] "SHaveProtos",
  52. [SNeedProto] "SNeedProto",
  53. [SHaveOK] "SHaveOK",
  54. [SRelay] "SRelay",
  55. };
  56. static int
  57. p9anyinit(Proto* p, Fsstate *fss)
  58. {
  59. int iscli;
  60. State *s;
  61. if((iscli = isclient(_strfindattr(fss->attr, "role"))) < 0)
  62. return failure(fss, nil);
  63. s = emalloc(sizeof *s);
  64. fss = fss;
  65. fss->phasename = phasenames;
  66. fss->maxphase = Maxphase;
  67. if(iscli)
  68. fss->phase = CNeedProtos;
  69. else
  70. fss->phase = SHaveProtos;
  71. s->version = 1;
  72. fss->ps = s;
  73. return RpcOk;
  74. }
  75. static void
  76. p9anyclose(Fsstate *fss)
  77. {
  78. State *s;
  79. s = fss->ps;
  80. if(s->subproto && s->subfss.ps && s->subproto->close)
  81. (*s->subproto->close)(&s->subfss);
  82. s->subproto = nil;
  83. s->substate = nil;
  84. s_free(s->subdom);
  85. s->subdom = nil;
  86. s->keyasked = 0;
  87. memset(&s->subfss, 0, sizeof s->subfss);
  88. free(s);
  89. }
  90. static void
  91. setupfss(Fsstate *fss, State *s, Key *k)
  92. {
  93. fss->attr = setattr(fss->attr, "proto=%q", s->subproto->name);
  94. fss->attr = setattr(fss->attr, "dom=%q", _strfindattr(k->attr, "dom"));
  95. s->subfss.attr = fss->attr;
  96. s->subfss.phase = Notstarted;
  97. s->subfss.sysuser = fss->sysuser;
  98. s->subfss.seqnum = fss->seqnum;
  99. s->subfss.conf = fss->conf;
  100. s->subfss.nconf = fss->nconf;
  101. }
  102. static int
  103. passret(Fsstate *fss, State *s, int ret)
  104. {
  105. switch(ret){
  106. default:
  107. return ret;
  108. case RpcFailure:
  109. if(s->subfss.phase == Broken)
  110. fss->phase = Broken;
  111. memmove(fss->err, s->subfss.err, sizeof fss->err);
  112. return ret;
  113. case RpcNeedkey:
  114. memmove(fss->keyinfo, s->subfss.keyinfo, sizeof fss->keyinfo);
  115. return ret;
  116. case RpcOk:
  117. if(s->subfss.haveai){
  118. fss->haveai = 1;
  119. fss->ai = s->subfss.ai;
  120. s->subfss.haveai = 0;
  121. }
  122. if(s->subfss.phase == Established)
  123. fss->phase = Established;
  124. return ret;
  125. case RpcToosmall:
  126. fss->rpc.nwant = s->subfss.rpc.nwant;
  127. return ret;
  128. case RpcConfirm:
  129. fss->conf = s->subfss.conf;
  130. fss->nconf = s->subfss.nconf;
  131. return ret;
  132. }
  133. }
  134. static int
  135. p9anyread(Fsstate *fss, void *a, uint *n)
  136. {
  137. int i, m, ophase, ret;
  138. Attr *anew;
  139. Key *k;
  140. Keyinfo ki;
  141. String *negstr;
  142. State *s;
  143. s = fss->ps;
  144. switch(fss->phase){
  145. default:
  146. return phaseerror(fss, "read");
  147. case SHaveProtos:
  148. m = 0;
  149. negstr = s_new();
  150. mkkeyinfo(&ki, fss, nil);
  151. ki.attr = nil;
  152. ki.noconf = 1;
  153. ki.user = nil;
  154. for(i=0; i<nelem(negotiable); i++){
  155. anew = setattr(_copyattr(fss->attr), "proto=%q dom?", negotiable[i]->name);
  156. ki.attr = anew;
  157. for(ki.skip=0; findkey(&k, &ki, nil)==RpcOk; ki.skip++){
  158. if(m++)
  159. s_append(negstr, " ");
  160. s_append(negstr, negotiable[i]->name);
  161. s_append(negstr, "@");
  162. s_append(negstr, _strfindattr(k->attr, "dom"));
  163. closekey(k);
  164. }
  165. _freeattr(anew);
  166. }
  167. if(m == 0){
  168. s_free(negstr);
  169. return failure(fss, Enegotiation);
  170. }
  171. i = s_len(negstr)+1;
  172. if(*n < i){
  173. s_free(negstr);
  174. return toosmall(fss, i);
  175. }
  176. *n = i;
  177. memmove(a, s_to_c(negstr), i+1);
  178. fss->phase = SNeedProto;
  179. s_free(negstr);
  180. return RpcOk;
  181. case CHaveProto:
  182. i = strlen(s->subproto->name)+1+s_len(s->subdom)+1;
  183. if(*n < i)
  184. return toosmall(fss, i);
  185. *n = i;
  186. strcpy(a, s->subproto->name);
  187. strcat(a, " ");
  188. strcat(a, s_to_c(s->subdom));
  189. if(s->version == 1)
  190. fss->phase = CRelay;
  191. else
  192. fss->phase = CNeedOK;
  193. return RpcOk;
  194. case SHaveOK:
  195. i = 3;
  196. if(*n < i)
  197. return toosmall(fss, i);
  198. *n = i;
  199. strcpy(a, "OK");
  200. fss->phase = SRelay;
  201. return RpcOk;
  202. case CRelay:
  203. case SRelay:
  204. ophase = s->subfss.phase;
  205. ret = (*s->subproto->read)(&s->subfss, a, n);
  206. rpcrdwrlog(&s->subfss, "read", *n, ophase, ret);
  207. return passret(fss, s, ret);
  208. }
  209. }
  210. static char*
  211. getdom(char *p)
  212. {
  213. p = strchr(p, '@');
  214. if(p == nil)
  215. return "";
  216. return p+1;
  217. }
  218. static Proto*
  219. findneg(char *name)
  220. {
  221. int i, len;
  222. char *p;
  223. if(p = strchr(name, '@'))
  224. len = p-name;
  225. else
  226. len = strlen(name);
  227. for(i=0; i<nelem(negotiable); i++)
  228. if(strncmp(negotiable[i]->name, name, len) == 0 && negotiable[i]->name[len] == 0)
  229. return negotiable[i];
  230. return nil;
  231. }
  232. static int
  233. p9anywrite(Fsstate *fss, void *va, uint n)
  234. {
  235. char *a, *dom, *user, *token[20];
  236. int asking, i, m, ophase, ret;
  237. Attr *anew, *anewsf, *attr;
  238. Key *k;
  239. Keyinfo ki;
  240. Proto *p;
  241. State *s;
  242. s = fss->ps;
  243. a = va;
  244. switch(fss->phase){
  245. default:
  246. return phaseerror(fss, "write");
  247. case CNeedProtos:
  248. if(n==0 || a[n-1] != '\0')
  249. return toosmall(fss, 2048);
  250. a = estrdup(a);
  251. m = tokenize(a, token, nelem(token));
  252. if(m > 0 && strncmp(token[0], "v.", 2) == 0){
  253. s->version = atoi(token[0]+2);
  254. if(s->version != 2){
  255. free(a);
  256. return failure(fss, "unknown version of p9any");
  257. }
  258. }
  259. /*
  260. * look for a key
  261. */
  262. anew = _delattr(_delattr(_copyattr(fss->attr), "proto"), "role");
  263. anewsf = _delattr(_copyattr(anew), "user");
  264. user = _strfindattr(anew, "user");
  265. k = nil;
  266. p = nil;
  267. dom = nil;
  268. for(i=(s->version==1?0:1); i<m; i++){
  269. p = findneg(token[i]);
  270. if(p == nil)
  271. continue;
  272. dom = getdom(token[i]);
  273. ret = RpcFailure;
  274. mkkeyinfo(&ki, fss, nil);
  275. if(user==nil || strcmp(user, fss->sysuser)==0){
  276. ki.attr = anewsf;
  277. ki.user = nil;
  278. ret = findkey(&k, &ki, "proto=%q dom=%q role=speakfor %s",
  279. p->name, dom, p->keyprompt);
  280. }
  281. if(ret == RpcFailure){
  282. ki.attr = anew;
  283. ki.user = fss->sysuser;
  284. ret = findkey(&k, &ki,
  285. "proto=%q dom=%q role=client %s",
  286. p->name, dom, p->keyprompt);
  287. }
  288. if(ret == RpcConfirm){
  289. free(a);
  290. return ret;
  291. }
  292. if(ret == RpcOk)
  293. break;
  294. }
  295. _freeattr(anewsf);
  296. /*
  297. * no acceptable key, go through the proto@domains one at a time.
  298. */
  299. asking = 0;
  300. if(k == nil){
  301. while(!asking && s->keyasked < m){
  302. p = findneg(token[s->keyasked]);
  303. if(p == nil){
  304. s->keyasked++;
  305. continue;
  306. }
  307. dom = getdom(token[s->keyasked]);
  308. mkkeyinfo(&ki, fss, nil);
  309. ki.attr = anew;
  310. ret = findkey(&k, &ki,
  311. "proto=%q dom=%q role=client %s",
  312. p->name, dom, p->keyprompt);
  313. s->keyasked++;
  314. if(ret == RpcNeedkey){
  315. asking = 1;
  316. break;
  317. }
  318. }
  319. }
  320. if(k == nil){
  321. free(a);
  322. _freeattr(anew);
  323. if(asking)
  324. return RpcNeedkey;
  325. else if(s->keyasked)
  326. return failure(fss, nil);
  327. else
  328. return failure(fss, Enegotiation);
  329. }
  330. s->subdom = s_copy(dom);
  331. s->subproto = p;
  332. free(a);
  333. _freeattr(anew);
  334. setupfss(fss, s, k);
  335. closekey(k);
  336. ret = (*s->subproto->init)(p, &s->subfss);
  337. rpcstartlog(s->subfss.attr, &s->subfss, ret);
  338. if(ret == RpcOk)
  339. fss->phase = CHaveProto;
  340. return passret(fss, s, ret);
  341. case SNeedProto:
  342. if(n==0 || a[n-1] != '\0')
  343. return toosmall(fss, n+1);
  344. a = estrdup(a);
  345. m = tokenize(a, token, nelem(token));
  346. if(m != 2){
  347. free(a);
  348. return failure(fss, Ebadarg);
  349. }
  350. p = findneg(token[0]);
  351. if(p == nil){
  352. free(a);
  353. return failure(fss, Enegotiation);
  354. }
  355. attr = _delattr(_copyattr(fss->attr), "proto");
  356. mkkeyinfo(&ki, fss, nil);
  357. ki.attr = attr;
  358. ki.user = nil;
  359. ret = findkey(&k, &ki, "proto=%q dom=%q role=server", token[0], token[1]);
  360. free(a);
  361. _freeattr(attr);
  362. if(ret == RpcConfirm)
  363. return ret;
  364. if(ret != RpcOk)
  365. return failure(fss, Enegotiation);
  366. s->subproto = p;
  367. setupfss(fss, s, k);
  368. closekey(k);
  369. ret = (*s->subproto->init)(p, &s->subfss);
  370. if(ret == RpcOk){
  371. if(s->version == 1)
  372. fss->phase = SRelay;
  373. else
  374. fss->phase = SHaveOK;
  375. }
  376. return passret(fss, s, ret);
  377. case CNeedOK:
  378. if(n < 3)
  379. return toosmall(fss, 3);
  380. if(strcmp("OK", a) != 0)
  381. return failure(fss, "server gave up");
  382. fss->phase = CRelay;
  383. return RpcOk;
  384. case CRelay:
  385. case SRelay:
  386. ophase = s->subfss.phase;
  387. ret = (*s->subproto->write)(&s->subfss, va, n);
  388. rpcrdwrlog(&s->subfss, "write", n, ophase, ret);
  389. return passret(fss, s, ret);
  390. }
  391. }
  392. Proto p9any =
  393. {
  394. .name= "p9any",
  395. .init= p9anyinit,
  396. .write= p9anywrite,
  397. .read= p9anyread,
  398. .close= p9anyclose,
  399. };