dial.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  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. * dial - connect to a service (parallel version)
  11. */
  12. #include <u.h>
  13. #include <libc.h>
  14. #include <ctype.h>
  15. typedef struct Conn Conn;
  16. typedef struct Dest Dest;
  17. typedef struct DS DS;
  18. enum
  19. {
  20. Maxstring = 128,
  21. Maxpath = 256,
  22. Maxcsreply = 64*80, /* this is probably overly generous */
  23. /*
  24. * this should be a plausible slight overestimate for non-interactive
  25. * use even if it's ridiculously long for interactive use.
  26. */
  27. Maxconnms = 2*60*1000, /* 2 minutes */
  28. };
  29. struct DS {
  30. /* dist string */
  31. char buf[Maxstring];
  32. char *netdir; /* e.g., /net.alt */
  33. char *proto; /* e.g., tcp */
  34. char *rem; /* e.g., host!service */
  35. /* other args */
  36. char *local;
  37. char *dir;
  38. int *cfdp;
  39. };
  40. /*
  41. * malloc these; they need to be writable by this proc & all children.
  42. * the stack is private to each proc, and static allocation in the data
  43. * segment would not permit concurrent dials within a multi-process program.
  44. */
  45. struct Conn {
  46. int pid;
  47. int dead;
  48. int dfd;
  49. int cfd;
  50. char dir[NETPATHLEN+1];
  51. char err[ERRMAX];
  52. };
  53. struct Dest {
  54. Conn *conn; /* allocated array */
  55. Conn *connend;
  56. int nkid;
  57. int32_t oalarm;
  58. int naddrs;
  59. QLock winlck;
  60. int winner; /* index into conn[] */
  61. char *nextaddr;
  62. char addrlist[Maxcsreply];
  63. };
  64. static int call(char*, char*, DS*, Dest*, Conn*);
  65. static int csdial(DS*);
  66. static void _dial_string_parse(char*, DS*);
  67. /*
  68. * the dialstring is of the form '[/net/]proto!dest'
  69. */
  70. static int
  71. dialimpl(char *dest, char *local, char *dir, int *cfdp)
  72. {
  73. DS ds;
  74. int rv;
  75. char err[ERRMAX], alterr[ERRMAX];
  76. ds.local = local;
  77. ds.dir = dir;
  78. ds.cfdp = cfdp;
  79. _dial_string_parse(dest, &ds);
  80. if(ds.netdir)
  81. return csdial(&ds);
  82. ds.netdir = "/net";
  83. rv = csdial(&ds);
  84. if(rv >= 0)
  85. return rv;
  86. err[0] = '\0';
  87. errstr(err, sizeof err);
  88. if(strstr(err, "refused") != 0){
  89. werrstr("%s", err);
  90. return rv;
  91. }
  92. ds.netdir = "/net.alt";
  93. rv = csdial(&ds);
  94. if(rv >= 0)
  95. return rv;
  96. alterr[0] = 0;
  97. errstr(alterr, sizeof alterr);
  98. if(strstr(alterr, "translate") || strstr(alterr, "does not exist"))
  99. werrstr("%s", err);
  100. else
  101. werrstr("%s", alterr);
  102. return rv;
  103. }
  104. /*
  105. * the thread library can't cope with rfork(RFMEM|RFPROC),
  106. * so it must override this with a private version of dial.
  107. */
  108. int (*_dial)(char *, char *, char *, int *) = dialimpl;
  109. int
  110. dial(char *dest, char *local, char *dir, int *cfdp)
  111. {
  112. return (*_dial)(dest, local, dir, cfdp);
  113. }
  114. static int
  115. connsalloc(Dest *dp, int addrs)
  116. {
  117. Conn *conn;
  118. free(dp->conn);
  119. dp->connend = nil;
  120. assert(addrs > 0);
  121. dp->conn = mallocz(addrs * sizeof *dp->conn, 1);
  122. if(dp->conn == nil)
  123. return -1;
  124. dp->connend = dp->conn + addrs;
  125. for(conn = dp->conn; conn < dp->connend; conn++)
  126. conn->cfd = conn->dfd = -1;
  127. return 0;
  128. }
  129. static void
  130. freedest(Dest *dp)
  131. {
  132. int32_t oalarm;
  133. if (dp == nil)
  134. return;
  135. oalarm = dp->oalarm;
  136. free(dp->conn);
  137. free(dp);
  138. if (oalarm >= 0)
  139. alarm(oalarm);
  140. }
  141. static void
  142. closeopenfd(int *fdp)
  143. {
  144. if (*fdp >= 0) {
  145. close(*fdp);
  146. *fdp = -1;
  147. }
  148. }
  149. static void
  150. notedeath(Dest *dp, char *exitsts)
  151. {
  152. int i, n, pid;
  153. char *fields[5]; /* pid + 3 times + error */
  154. Conn *conn;
  155. for (i = 0; i < nelem(fields); i++)
  156. fields[i] = "";
  157. n = tokenize(exitsts, fields, nelem(fields));
  158. if (n < 4)
  159. return;
  160. pid = atoi(fields[0]);
  161. if (pid <= 0)
  162. return;
  163. for (conn = dp->conn; conn < dp->connend; conn++)
  164. if (conn->pid == pid && !conn->dead) { /* it's one we know? */
  165. if (conn - dp->conn != dp->winner) {
  166. closeopenfd(&conn->dfd);
  167. closeopenfd(&conn->cfd);
  168. }
  169. strncpy(conn->err, fields[4], sizeof conn->err - 1);
  170. conn->err[sizeof conn->err - 1] = '\0';
  171. conn->dead = 1;
  172. return;
  173. }
  174. /* not a proc that we forked */
  175. }
  176. static int
  177. outstandingprocs(Dest *dp)
  178. {
  179. Conn *conn;
  180. for (conn = dp->conn; conn < dp->connend; conn++)
  181. if (!conn->dead)
  182. return 1;
  183. return 0;
  184. }
  185. static int
  186. reap(Dest *dp)
  187. {
  188. char exitsts[2*ERRMAX];
  189. if (outstandingprocs(dp) && await(exitsts, sizeof exitsts) >= 0) {
  190. notedeath(dp, exitsts);
  191. return 0;
  192. }
  193. return -1;
  194. }
  195. static int
  196. fillinds(DS *ds, Dest *dp)
  197. {
  198. Conn *conn;
  199. if (dp->winner < 0)
  200. return -1;
  201. conn = &dp->conn[dp->winner];
  202. if (ds->cfdp)
  203. *ds->cfdp = conn->cfd;
  204. if (ds->dir) {
  205. strncpy(ds->dir, conn->dir, NETPATHLEN);
  206. ds->dir[NETPATHLEN-1] = '\0';
  207. }
  208. return conn->dfd;
  209. }
  210. static int
  211. connectwait(Dest *dp, char *besterr)
  212. {
  213. Conn *conn;
  214. /* wait for a winner or all attempts to time out */
  215. while (dp->winner < 0 && reap(dp) >= 0)
  216. ;
  217. /* kill all of our still-live kids & reap them */
  218. for (conn = dp->conn; conn < dp->connend; conn++)
  219. if (!conn->dead)
  220. postnote(PNPROC, conn->pid, "alarm");
  221. while (reap(dp) >= 0)
  222. ;
  223. /* rummage about and report some error string */
  224. for (conn = dp->conn; conn < dp->connend; conn++)
  225. if (conn - dp->conn != dp->winner && conn->dead &&
  226. conn->err[0]) {
  227. strncpy(besterr, conn->err, ERRMAX-1);
  228. conn->err[ERRMAX-1] = '\0';
  229. break;
  230. }
  231. return dp->winner;
  232. }
  233. static int
  234. parsecs(Dest *dp, char **clonep, char **destp)
  235. {
  236. char *dest, *p;
  237. dest = strchr(dp->nextaddr, ' ');
  238. if(dest == nil)
  239. return -1;
  240. *dest++ = '\0';
  241. p = strchr(dest, '\n');
  242. if(p == nil)
  243. return -1;
  244. *p++ = '\0';
  245. *clonep = dp->nextaddr;
  246. *destp = dest;
  247. dp->nextaddr = p; /* advance to next line */
  248. return 0;
  249. }
  250. static void
  251. pickuperr(char *besterr, char *err)
  252. {
  253. err[0] = '\0';
  254. errstr(err, ERRMAX);
  255. if(strstr(err, "does not exist") == 0)
  256. strcpy(besterr, err);
  257. }
  258. static int
  259. catcher(void *, char *s)
  260. {
  261. return strstr(s, "alarm") != nil;
  262. }
  263. /*
  264. * try all addresses in parallel and take the first one that answers;
  265. * this helps when systems have ip v4 and v6 addresses but are
  266. * only reachable from here on one (or some) of them.
  267. */
  268. static int
  269. dialmulti(DS *ds, Dest *dp)
  270. {
  271. int rv, kid, kidme;
  272. char *clone, *dest;
  273. char err[ERRMAX], besterr[ERRMAX];
  274. dp->winner = -1;
  275. dp->nkid = 0;
  276. while(dp->winner < 0 && *dp->nextaddr != '\0' &&
  277. parsecs(dp, &clone, &dest) >= 0) {
  278. kidme = dp->nkid++; /* make private copy on stack */
  279. kid = rfork(RFPROC|RFMEM); /* spin off a call attempt */
  280. if (kid < 0)
  281. --dp->nkid;
  282. else if (kid == 0) {
  283. /* only in kid, to avoid atnotify callbacks in parent */
  284. atnotify(catcher, 1);
  285. *besterr = '\0';
  286. rv = call(clone, dest, ds, dp, &dp->conn[kidme]);
  287. if(rv < 0)
  288. pickuperr(besterr, err);
  289. _exits(besterr); /* avoid atexit callbacks */
  290. }
  291. }
  292. rv = connectwait(dp, besterr);
  293. if(rv < 0 && *besterr)
  294. werrstr("%s", besterr);
  295. else
  296. werrstr("%s", err);
  297. return rv;
  298. }
  299. static int
  300. csdial(DS *ds)
  301. {
  302. int n, fd, rv, addrs, bleft;
  303. char c;
  304. char *addrp, *clone2, *dest;
  305. char buf[Maxstring], clone[Maxpath], err[ERRMAX], besterr[ERRMAX];
  306. Dest *dp;
  307. dp = mallocz(sizeof *dp, 1);
  308. if(dp == nil)
  309. return -1;
  310. dp->winner = -1;
  311. dp->oalarm = alarm(0);
  312. if (connsalloc(dp, 1) < 0) { /* room for a single conn. */
  313. freedest(dp);
  314. return -1;
  315. }
  316. /*
  317. * open connection server
  318. */
  319. snprint(buf, sizeof(buf), "%s/cs", ds->netdir);
  320. fd = open(buf, ORDWR);
  321. if(fd < 0){
  322. /* no connection server, don't translate */
  323. snprint(clone, sizeof(clone), "%s/%s/clone", ds->netdir, ds->proto);
  324. rv = call(clone, ds->rem, ds, dp, &dp->conn[0]);
  325. fillinds(ds, dp);
  326. freedest(dp);
  327. return rv;
  328. }
  329. /*
  330. * ask connection server to translate
  331. */
  332. snprint(buf, sizeof(buf), "%s!%s", ds->proto, ds->rem);
  333. if(write(fd, buf, strlen(buf)) < 0){
  334. close(fd);
  335. freedest(dp);
  336. return -1;
  337. }
  338. /*
  339. * read all addresses from the connection server.
  340. */
  341. seek(fd, 0, 0);
  342. addrs = 0;
  343. addrp = dp->nextaddr = dp->addrlist;
  344. bleft = sizeof dp->addrlist - 2; /* 2 is room for \n\0 */
  345. while(bleft > 0 && (n = read(fd, addrp, bleft)) > 0) {
  346. if (addrp[n-1] != '\n')
  347. addrp[n++] = '\n';
  348. addrs++;
  349. addrp += n;
  350. bleft -= n;
  351. }
  352. /*
  353. * if we haven't read all of cs's output, assume the last line might
  354. * have been truncated and ignore it. we really don't expect this
  355. * to happen.
  356. */
  357. if (addrs > 0 && bleft <= 0 && read(fd, &c, 1) == 1)
  358. addrs--;
  359. close(fd);
  360. *besterr = 0;
  361. rv = -1; /* pessimistic default */
  362. dp->naddrs = addrs;
  363. if (addrs == 0)
  364. werrstr("no address to dial");
  365. else if (addrs == 1) {
  366. /* common case: dial one address without forking */
  367. if (parsecs(dp, &clone2, &dest) >= 0 &&
  368. (rv = call(clone2, dest, ds, dp, &dp->conn[0])) < 0) {
  369. pickuperr(besterr, err);
  370. werrstr("%s", besterr);
  371. }
  372. } else if (connsalloc(dp, addrs) >= 0)
  373. rv = dialmulti(ds, dp);
  374. /* fill in results */
  375. if (rv >= 0 && dp->winner >= 0)
  376. rv = fillinds(ds, dp);
  377. freedest(dp);
  378. return rv;
  379. }
  380. static int
  381. call(char *clone, char *dest, DS *ds, Dest *dp, Conn *conn)
  382. {
  383. int fd, cfd, n, calleralarm, oalarm;
  384. char cname[Maxpath], name[Maxpath], data[Maxpath], *p;
  385. /* because cs is in a different name space, replace the mount point */
  386. if(*clone == '/'){
  387. p = strchr(clone+1, '/');
  388. if(p == nil)
  389. p = clone;
  390. else
  391. p++;
  392. } else
  393. p = clone;
  394. snprint(cname, sizeof cname, "%s/%s", ds->netdir, p);
  395. conn->pid = getpid();
  396. conn->cfd = cfd = open(cname, ORDWR);
  397. if(cfd < 0)
  398. return -1;
  399. /* get directory name */
  400. n = read(cfd, name, sizeof(name)-1);
  401. if(n < 0){
  402. closeopenfd(&conn->cfd);
  403. return -1;
  404. }
  405. name[n] = 0;
  406. for(p = name; *p == ' '; p++)
  407. ;
  408. snprint(name, sizeof(name), "%ld", strtoul(p, 0, 0));
  409. p = strrchr(cname, '/');
  410. *p = 0;
  411. if(ds->dir)
  412. snprint(conn->dir, NETPATHLEN, "%s/%s", cname, name);
  413. snprint(data, sizeof(data), "%s/%s/data", cname, name);
  414. /* should be no alarm pending now; re-instate caller's alarm, if any */
  415. calleralarm = dp->oalarm > 0;
  416. if (calleralarm)
  417. alarm(dp->oalarm);
  418. else if (dp->naddrs > 1) /* in a sub-process? */
  419. alarm(Maxconnms);
  420. /* connect */
  421. if(ds->local)
  422. snprint(name, sizeof(name), "connect %s %s", dest, ds->local);
  423. else
  424. snprint(name, sizeof(name), "connect %s", dest);
  425. if(write(cfd, name, strlen(name)) < 0){
  426. closeopenfd(&conn->cfd);
  427. return -1;
  428. }
  429. oalarm = alarm(0); /* don't let alarm interrupt critical section */
  430. if (calleralarm)
  431. dp->oalarm = oalarm; /* time has passed, so update user's */
  432. /* open data connection */
  433. conn->dfd = fd = open(data, ORDWR);
  434. if(fd < 0){
  435. closeopenfd(&conn->cfd);
  436. alarm(dp->oalarm);
  437. return -1;
  438. }
  439. if(ds->cfdp == nil)
  440. closeopenfd(&conn->cfd);
  441. n = conn - dp->conn;
  442. if (dp->winner < 0) {
  443. qlock(&dp->winlck);
  444. if (dp->winner < 0 && conn < dp->connend)
  445. dp->winner = n;
  446. qunlock(&dp->winlck);
  447. }
  448. alarm(calleralarm? dp->oalarm: 0);
  449. return fd;
  450. }
  451. /*
  452. * assume p points at first '!' in dial string. st is start of dial string.
  453. * there could be subdirs of the conn dirs (e.g., ssh/0) that must count as
  454. * part of the proto string, so skip numeric components.
  455. * returns pointer to delimiter after right-most non-numeric component.
  456. */
  457. static char *
  458. backoverchans(char *st, char *p)
  459. {
  460. char *sl;
  461. for (sl = p; --p >= st && isascii(*p) && isdigit(*p); sl = p) {
  462. while (--p >= st && isascii(*p) && isdigit(*p))
  463. ;
  464. if (p < st || *p != '/')
  465. break; /* "net.alt2" or ran off start */
  466. while (p > st && p[-1] == '/') /* skip runs of slashes */
  467. p--;
  468. }
  469. return sl;
  470. }
  471. /*
  472. * parse a dial string
  473. */
  474. static void
  475. _dial_string_parse(char *str, DS *ds)
  476. {
  477. char *p, *p2;
  478. strncpy(ds->buf, str, Maxstring);
  479. ds->buf[Maxstring-1] = 0;
  480. p = strchr(ds->buf, '!');
  481. if(p == 0) {
  482. ds->netdir = 0;
  483. ds->proto = "net";
  484. ds->rem = ds->buf;
  485. } else {
  486. if(*ds->buf != '/' && *ds->buf != '#'){
  487. ds->netdir = 0;
  488. ds->proto = ds->buf;
  489. } else {
  490. p2 = backoverchans(ds->buf, p);
  491. /* back over last component of netdir (proto) */
  492. while (--p2 > ds->buf && *p2 != '/')
  493. ;
  494. *p2++ = 0;
  495. ds->netdir = ds->buf;
  496. ds->proto = p2;
  497. }
  498. *p = 0;
  499. ds->rem = p + 1;
  500. }
  501. }