dial.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  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. while((n = read(fd, buf, sizeof(buf) - 1)) > 0){
  91. buf[n] = 0;
  92. p = strchr(buf, ' ');
  93. if(p == 0)
  94. continue;
  95. *p++ = 0;
  96. rv = call(buf, p, ds);
  97. if(rv >= 0)
  98. break;
  99. err[0] = '\0';
  100. errstr(err, sizeof err);
  101. if(strstr(err, "does not exist") == 0)
  102. strcpy(besterr, err);
  103. }
  104. close(fd);
  105. if(rv < 0 && *besterr)
  106. werrstr("%s", besterr);
  107. else
  108. werrstr("%s", err);
  109. return rv;
  110. }
  111. static int
  112. call(char *clone, char *dest, DS *ds)
  113. {
  114. int fd, cfd, n;
  115. char name[Maxpath], data[Maxpath], *p;
  116. cfd = open(clone, ORDWR);
  117. if(cfd < 0)
  118. return -1;
  119. /* get directory name */
  120. n = read(cfd, name, sizeof(name)-1);
  121. if(n < 0){
  122. close(cfd);
  123. return -1;
  124. }
  125. name[n] = 0;
  126. for(p = name; *p == ' '; p++)
  127. ;
  128. snprint(name, sizeof(name), "%ld", strtoul(p, 0, 0));
  129. p = strrchr(clone, '/');
  130. *p = 0;
  131. if(ds->dir)
  132. snprint(ds->dir, NETPATHLEN, "%s/%s", clone, name);
  133. snprint(data, sizeof(data), "%s/%s/data", clone, name);
  134. /* connect */
  135. if(ds->local)
  136. snprint(name, sizeof(name), "connect %s %s", dest, ds->local);
  137. else
  138. snprint(name, sizeof(name), "connect %s", dest);
  139. if(write(cfd, name, strlen(name)) < 0){
  140. close(cfd);
  141. return -1;
  142. }
  143. /* open data connection */
  144. fd = open(data, ORDWR);
  145. if(fd < 0){
  146. close(cfd);
  147. return -1;
  148. }
  149. if(ds->cfdp)
  150. *ds->cfdp = cfd;
  151. else
  152. close(cfd);
  153. return fd;
  154. }
  155. /*
  156. * parse a dial string
  157. */
  158. static void
  159. _dial_string_parse(char *str, DS *ds)
  160. {
  161. char *p, *p2;
  162. strncpy(ds->buf, str, Maxstring);
  163. ds->buf[Maxstring-1] = 0;
  164. p = strchr(ds->buf, '!');
  165. if(p == 0) {
  166. ds->netdir = 0;
  167. ds->proto = "net";
  168. ds->rem = ds->buf;
  169. } else {
  170. if(*ds->buf != '/' && *ds->buf != '#'){
  171. ds->netdir = 0;
  172. ds->proto = ds->buf;
  173. } else {
  174. for(p2 = p; *p2 != '/'; p2--)
  175. ;
  176. *p2++ = 0;
  177. ds->netdir = ds->buf;
  178. ds->proto = p2;
  179. }
  180. *p = 0;
  181. ds->rem = p + 1;
  182. }
  183. }