p9any.c 8.7 KB

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