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