dial.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. #include <u.h>
  2. #include <libc.h>
  3. typedef struct DS DS;
  4. static int call(char*, char*, DS*);
  5. static int csdial(DS*);
  6. static void _dial_string_parse(char*, DS*);
  7. enum
  8. {
  9. Maxstring = 128,
  10. Maxpath = 256,
  11. };
  12. struct DS {
  13. /* dist string */
  14. char buf[Maxstring];
  15. char *netdir;
  16. char *proto;
  17. char *rem;
  18. /* other args */
  19. char *local;
  20. char *dir;
  21. int *cfdp;
  22. };
  23. /*
  24. * the dialstring is of the form '[/net/]proto!dest'
  25. */
  26. int
  27. dial(char *dest, char *local, char *dir, int *cfdp)
  28. {
  29. DS ds;
  30. int rv;
  31. char err[ERRMAX], alterr[ERRMAX];
  32. ds.local = local;
  33. ds.dir = dir;
  34. ds.cfdp = cfdp;
  35. _dial_string_parse(dest, &ds);
  36. if(ds.netdir)
  37. return csdial(&ds);
  38. ds.netdir = "/net";
  39. rv = csdial(&ds);
  40. if(rv >= 0)
  41. return rv;
  42. err[0] = '\0';
  43. errstr(err, sizeof err);
  44. if(strstr(err, "refused") != 0){
  45. werrstr("%s", err);
  46. return rv;
  47. }
  48. ds.netdir = "/net.alt";
  49. rv = csdial(&ds);
  50. if(rv >= 0)
  51. return rv;
  52. alterr[0] = 0;
  53. errstr(alterr, sizeof alterr);
  54. if(strstr(alterr, "translate") || strstr(alterr, "does not exist"))
  55. werrstr("%s", err);
  56. else
  57. werrstr("%s", alterr);
  58. return rv;
  59. }
  60. static int
  61. csdial(DS *ds)
  62. {
  63. int n, fd, rv;
  64. char *p, buf[Maxstring], clone[Maxpath], err[ERRMAX], besterr[ERRMAX];
  65. /*
  66. * open connection server
  67. */
  68. snprint(buf, sizeof(buf), "%s/cs", ds->netdir);
  69. fd = open(buf, ORDWR);
  70. if(fd < 0){
  71. /* no connection server, don't translate */
  72. snprint(clone, sizeof(clone), "%s/%s/clone", ds->netdir, ds->proto);
  73. return call(clone, ds->rem, ds);
  74. }
  75. /*
  76. * ask connection server to translate
  77. */
  78. snprint(buf, sizeof(buf), "%s!%s", ds->proto, ds->rem);
  79. if(write(fd, buf, strlen(buf)) < 0){
  80. close(fd);
  81. return -1;
  82. }
  83. /*
  84. * loop through each address from the connection server till
  85. * we get one that works.
  86. */
  87. *besterr = 0;
  88. rv = -1;
  89. seek(fd, 0, 0);
  90. strcpy(err, "cs gave empty translation list");
  91. while((n = read(fd, buf, sizeof(buf) - 1)) > 0){
  92. buf[n] = 0;
  93. p = strchr(buf, ' ');
  94. if(p == 0)
  95. continue;
  96. *p++ = 0;
  97. rv = call(buf, p, ds);
  98. if(rv >= 0)
  99. break;
  100. err[0] = '\0';
  101. errstr(err, sizeof err);
  102. if(strstr(err, "does not exist") == 0)
  103. strcpy(besterr, err);
  104. }
  105. close(fd);
  106. if(rv < 0 && *besterr)
  107. werrstr("%s", besterr);
  108. else
  109. werrstr("%s", err);
  110. return rv;
  111. }
  112. static int
  113. call(char *clone, char *dest, DS *ds)
  114. {
  115. int fd, cfd, n;
  116. char name[Maxpath], data[Maxpath], *p;
  117. cfd = open(clone, ORDWR);
  118. if(cfd < 0)
  119. return -1;
  120. /* get directory name */
  121. n = read(cfd, name, sizeof(name)-1);
  122. if(n < 0){
  123. close(cfd);
  124. return -1;
  125. }
  126. name[n] = 0;
  127. for(p = name; *p == ' '; p++)
  128. ;
  129. snprint(name, sizeof(name), "%ld", strtoul(p, 0, 0));
  130. p = strrchr(clone, '/');
  131. *p = 0;
  132. if(ds->dir)
  133. snprint(ds->dir, NETPATHLEN, "%s/%s", clone, name);
  134. snprint(data, sizeof(data), "%s/%s/data", clone, name);
  135. /* connect */
  136. if(ds->local)
  137. snprint(name, sizeof(name), "connect %s %s", dest, ds->local);
  138. else
  139. snprint(name, sizeof(name), "connect %s", dest);
  140. if(write(cfd, name, strlen(name)) < 0){
  141. close(cfd);
  142. return -1;
  143. }
  144. /* open data connection */
  145. fd = open(data, ORDWR);
  146. if(fd < 0){
  147. print("open %s: %r\n", data);
  148. close(cfd);
  149. return -1;
  150. }
  151. if(ds->cfdp)
  152. *ds->cfdp = cfd;
  153. else
  154. close(cfd);
  155. return fd;
  156. }
  157. /*
  158. * parse a dial string
  159. */
  160. static void
  161. _dial_string_parse(char *str, DS *ds)
  162. {
  163. char *p, *p2;
  164. strncpy(ds->buf, str, Maxstring);
  165. ds->buf[Maxstring-1] = 0;
  166. p = strchr(ds->buf, '!');
  167. if(p == 0) {
  168. ds->netdir = 0;
  169. ds->proto = "net";
  170. ds->rem = ds->buf;
  171. } else {
  172. if(*ds->buf != '/' && *ds->buf != '#'){
  173. ds->netdir = 0;
  174. ds->proto = ds->buf;
  175. } else {
  176. for(p2 = p; *p2 != '/'; p2--)
  177. ;
  178. *p2++ = 0;
  179. ds->netdir = ds->buf;
  180. ds->proto = p2;
  181. }
  182. *p = 0;
  183. ds->rem = p + 1;
  184. }
  185. }