1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "../port/error.h" 7 #include "kernel.h" 8 9 typedef struct DS DS; 10 11 static int call(char*, char*, DS*); 12 static int csdial(DS*); 13 static void _dial_string_parse(char*, DS*); 14 static int nettrans(char*, char*, int na, char*, int); 15 16 enum 17 { 18 Maxstring= 128, 19 Maxpath= 100 20 }; 21 22 struct DS 23 { 24 char buf[Maxstring]; /* dist string */ 25 char *netdir; 26 char *proto; 27 char *rem; 28 char *local; /* other args */ 29 char *dir; 30 int *cfdp; 31 }; 32 33 /* 34 * the dialstring is of the form '[/net/]proto!dest' 35 */ 36 int 37 kdial(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 56 err[0] = 0; 57 kerrstr(err, sizeof err); 58 if(strstr(err, "refused") != 0){ 59 kerrstr(err, sizeof err); 60 return rv; 61 } 62 63 ds.netdir = "/net.alt"; 64 rv = csdial(&ds); 65 if(rv >= 0) 66 return rv; 67 68 alterr[0] = 0; 69 kerrstr(alterr, sizeof err); 70 71 if(strstr(alterr, "translate") || strstr(alterr, "does not exist")) 72 kerrstr(err, sizeof err); 73 else 74 kerrstr(alterr, sizeof alterr); 75 return rv; 76 } 77 78 static int 79 csdial(DS *ds) 80 { 81 int n, fd, rv; 82 char *p, buf[Maxstring], clone[Maxpath], err[ERRMAX], besterr[ERRMAX]; 83 84 /* 85 * open connection server 86 */ 87 snprint(buf, sizeof(buf), "%s/cs", ds->netdir); 88 fd = kopen(buf, ORDWR); 89 if(fd < 0){ 90 /* no connection server, don't translate */ 91 snprint(clone, sizeof(clone), "%s/%s/clone", ds->netdir, ds->proto); 92 return call(clone, ds->rem, ds); 93 } 94 95 /* 96 * ask connection server to translate 97 */ 98 sprint(buf, "%s!%s", ds->proto, ds->rem); 99 if(kwrite(fd, buf, strlen(buf)) < 0){ 100 kerrstr(err, sizeof err); 101 kclose(fd); 102 kwerrstr("%s (%s)", err, buf); 103 return -1; 104 } 105 106 /* 107 * loop through each address from the connection server till 108 * we get one that works. 109 */ 110 *besterr = 0; 111 strcpy(err, Egreg); 112 rv = -1; 113 kseek(fd, 0, 0); 114 while((n = kread(fd, buf, sizeof(buf) - 1)) > 0){ 115 buf[n] = 0; 116 p = strchr(buf, ' '); 117 if(p == 0) 118 continue; 119 *p++ = 0; 120 rv = call(buf, p, ds); 121 if(rv >= 0) 122 break; 123 err[0] = 0; 124 kerrstr(err, sizeof err); 125 if(strstr(err, "does not exist") == 0) 126 memmove(besterr, err, sizeof besterr); 127 } 128 kclose(fd); 129 130 if(rv < 0 && *besterr) 131 kerrstr(besterr, sizeof besterr); 132 else 133 kerrstr(err, sizeof err); 134 return rv; 135 } 136 137 static int 138 call(char *clone, char *dest, DS *ds) 139 { 140 int fd, cfd, n; 141 char name[Maxpath], data[Maxpath], err[ERRMAX], *p; 142 143 cfd = kopen(clone, ORDWR); 144 if(cfd < 0){ 145 kerrstr(err, sizeof err); 146 kwerrstr("%s (%s)", err, clone); 147 return -1; 148 } 149 150 /* get directory name */ 151 n = kread(cfd, name, sizeof(name)-1); 152 if(n < 0){ 153 kerrstr(err, sizeof err); 154 kclose(cfd); 155 kwerrstr("read %s: %s", clone, err); 156 return -1; 157 } 158 name[n] = 0; 159 for(p = name; *p == ' '; p++) 160 ; 161 sprint(name, "%ld", strtoul(p, 0, 0)); 162 p = strrchr(clone, '/'); 163 *p = 0; 164 if(ds->dir) 165 snprint(ds->dir, NETPATHLEN, "%s/%s", clone, name); 166 snprint(data, sizeof(data), "%s/%s/data", clone, 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(kwrite(cfd, name, strlen(name)) < 0){ 174 err[0] = 0; 175 kerrstr(err, sizeof err); 176 kclose(cfd); 177 kwerrstr("%s (%s)", err, name); 178 return -1; 179 } 180 181 /* open data connection */ 182 fd = kopen(data, ORDWR); 183 if(fd < 0){ 184 err[0] = 0; 185 kerrstr(err, sizeof err); 186 kwerrstr("%s (%s)", err, data); 187 kclose(cfd); 188 return -1; 189 } 190 if(ds->cfdp) 191 *ds->cfdp = cfd; 192 else 193 kclose(cfd); 194 195 return fd; 196 } 197 198 /* 199 * parse a dial string 200 */ 201 static void 202 _dial_string_parse(char *str, DS *ds) 203 { 204 char *p, *p2; 205 206 strncpy(ds->buf, str, Maxstring); 207 ds->buf[Maxstring-1] = 0; 208 209 p = strchr(ds->buf, '!'); 210 if(p == 0) { 211 ds->netdir = 0; 212 ds->proto = "net"; 213 ds->rem = ds->buf; 214 } else { 215 if(*ds->buf != '/' && *ds->buf != '#'){ 216 ds->netdir = 0; 217 ds->proto = ds->buf; 218 } else { 219 for(p2 = p; *p2 != '/'; p2--) 220 ; 221 *p2++ = 0; 222 ds->netdir = ds->buf; 223 ds->proto = p2; 224 } 225 *p = 0; 226 ds->rem = p + 1; 227 } 228 } 229 230 /* 231 * announce a network service. 232 */ 233 int 234 kannounce(char *addr, char *dir) 235 { 236 int ctl, n, m; 237 char buf[NETPATHLEN]; 238 char buf2[Maxpath]; 239 char netdir[NETPATHLEN]; 240 char naddr[Maxpath]; 241 char *cp; 242 243 /* 244 * translate the address 245 */ 246 if(nettrans(addr, naddr, sizeof(naddr), netdir, sizeof(netdir)) < 0) 247 return -1; 248 249 /* 250 * get a control channel 251 */ 252 ctl = kopen(netdir, ORDWR); 253 if(ctl<0) 254 return -1; 255 cp = strrchr(netdir, '/'); 256 *cp = 0; 257 258 /* 259 * find out which line we have 260 */ 261 n = sprint(buf, "%.*s/", sizeof buf, netdir); 262 m = kread(ctl, &buf[n], sizeof(buf)-n-1); 263 if(m <= 0){ 264 kclose(ctl); 265 return -1; 266 } 267 buf[n+m] = 0; 268 269 /* 270 * make the call 271 */ 272 n = snprint(buf2, sizeof buf2, "announce %s", naddr); 273 if(kwrite(ctl, buf2, n)!=n){ 274 kclose(ctl); 275 return -1; 276 } 277 278 /* 279 * return directory etc. 280 */ 281 if(dir) 282 strcpy(dir, buf); 283 return ctl; 284 } 285 286 /* 287 * listen for an incoming call 288 */ 289 int 290 klisten(char *dir, char *newdir) 291 { 292 int ctl, n, m; 293 char buf[NETPATHLEN]; 294 char *cp; 295 296 /* 297 * open listen, wait for a call 298 */ 299 snprint(buf, sizeof buf, "%s/listen", dir); 300 ctl = kopen(buf, ORDWR); 301 if(ctl < 0) 302 return -1; 303 304 /* 305 * find out which line we have 306 */ 307 strcpy(buf, dir); 308 cp = strrchr(buf, '/'); 309 *++cp = 0; 310 n = cp-buf; 311 m = kread(ctl, cp, sizeof(buf) - n - 1); 312 if(m <= 0){ 313 kclose(ctl); 314 return -1; 315 } 316 buf[n+m] = 0; 317 318 /* 319 * return directory etc. 320 */ 321 if(newdir) 322 strcpy(newdir, buf); 323 return ctl; 324 325 } 326 327 /* 328 * perform the identity translation (in case we can't reach cs) 329 */ 330 static int 331 identtrans(char *netdir, char *addr, char *naddr, int na, char *file, int nf) 332 { 333 char proto[Maxpath]; 334 char *p; 335 336 USED(nf); 337 338 /* parse the protocol */ 339 strncpy(proto, addr, sizeof(proto)); 340 proto[sizeof(proto)-1] = 0; 341 p = strchr(proto, '!'); 342 if(p) 343 *p++ = 0; 344 345 snprint(file, nf, "%s/%s/clone", netdir, proto); 346 strncpy(naddr, p, na); 347 naddr[na-1] = 0; 348 349 return 1; 350 } 351 352 /* 353 * call up the connection server and get a translation 354 */ 355 static int 356 nettrans(char *addr, char *naddr, int na, char *file, int nf) 357 { 358 int i, fd; 359 char buf[Maxpath]; 360 char netdir[NETPATHLEN]; 361 char *p, *p2; 362 long n; 363 364 /* 365 * parse, get network directory 366 */ 367 p = strchr(addr, '!'); 368 if(p == 0){ 369 kwerrstr("bad dial string: %s", addr); 370 return -1; 371 } 372 if(*addr != '/'){ 373 strcpy(netdir, "/net"); 374 } else { 375 for(p2 = p; *p2 != '/'; p2--) 376 ; 377 i = p2 - addr; 378 if(i == 0 || i >= sizeof(netdir)){ 379 kwerrstr("bad dial string: %s", addr); 380 return -1; 381 } 382 strncpy(netdir, addr, i); 383 netdir[i] = 0; 384 addr = p2 + 1; 385 } 386 387 /* 388 * ask the connection server 389 */ 390 sprint(buf, "%s/cs", netdir); 391 fd = kopen(buf, ORDWR); 392 if(fd < 0) 393 return identtrans(netdir, addr, naddr, na, file, nf); 394 if(kwrite(fd, addr, strlen(addr)) < 0){ 395 kclose(fd); 396 return -1; 397 } 398 kseek(fd, 0, 0); 399 n = kread(fd, buf, sizeof(buf)-1); 400 kclose(fd); 401 if(n <= 0) 402 return -1; 403 buf[n] = 0; 404 405 /* 406 * parse the reply 407 */ 408 p = strchr(buf, ' '); 409 if(p == 0) 410 return -1; 411 *p++ = 0; 412 strncpy(naddr, p, na); 413 naddr[na-1] = 0; 414 415 if(buf[0] == '/'){ 416 p = strchr(buf+1, '/'); 417 if(p == nil) 418 p = buf; 419 else 420 p++; 421 } 422 snprint(file, nf, "%s/%s", netdir, p); 423 return 0; 424 } 425