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