|  | /* | 
|  | * This file is part of the UCB release of Plan 9. It is subject to the license | 
|  | * terms in the LICENSE file found in the top-level directory of this | 
|  | * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No | 
|  | * part of the UCB release of Plan 9, including this file, may be copied, | 
|  | * modified, propagated, or distributed except according to the terms contained | 
|  | * in the LICENSE file. | 
|  | */ | 
|  | #include <stdlib.h> | 
|  |  | 
|  | #include <fcntl.h> | 
|  | #include <stdio.h> | 
|  | #include <string.h> | 
|  | #include <sys/types.h> | 
|  | #include <unistd.h> | 
|  | #include <iplib/iplib.h> | 
|  |  | 
|  | #define NAMELEN 28 | 
|  |  | 
|  | static int isdigit(int c) | 
|  | { | 
|  | return ((c >= '0' && c <= '9')); | 
|  | } | 
|  |  | 
|  | static int call(char *clone, char *dest, int *cfdp, char *dir, char *local, | 
|  | int flags) | 
|  | { | 
|  | int fd, cfd; | 
|  | int n; | 
|  | char name[3 * NAMELEN + 5]; | 
|  | char data[3 * NAMELEN + 10]; | 
|  | char *p; | 
|  |  | 
|  | cfd = open(clone, O_RDWR); | 
|  | if (cfd < 0) | 
|  | return -1; | 
|  |  | 
|  | /* get directory name */ | 
|  | n = read(cfd, name, sizeof(name) - 1); | 
|  | if (n < 0) { | 
|  | close(cfd); | 
|  | return -1; | 
|  | } | 
|  | name[n] = 0; | 
|  | p = strrchr(clone, '/'); | 
|  | *p = 0; | 
|  | if (dir) | 
|  | sprintf(dir, "%.*s/%.*s", 2 * NAMELEN + 1, clone, NAMELEN, | 
|  | name); | 
|  | sprintf(data, "%.*s/%.*s/data", 2 * NAMELEN + 1, clone, NAMELEN, name); | 
|  |  | 
|  | /* set local side (port number, for example) if we need to */ | 
|  | if (local) | 
|  | sprintf(name, "connect %.*s %.*s", 2 * NAMELEN, dest, NAMELEN, | 
|  | local); | 
|  | else | 
|  | sprintf(name, "connect %.*s", 2 * NAMELEN, dest); | 
|  | /* connect */ | 
|  | if (write(cfd, name, strlen(name)) < 0) { | 
|  | close(cfd); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | /* open data connection */ | 
|  | fd = open(data, O_RDWR | (flags & O_NONBLOCK)); | 
|  | if (fd < 0) { | 
|  | close(cfd); | 
|  | return -1; | 
|  | } | 
|  | if (cfdp) | 
|  | *cfdp = cfd; | 
|  | else | 
|  | close(cfd); | 
|  | return fd; | 
|  | } | 
|  |  | 
|  | int dial9(char *dest, char *local, char *dir, int *cfdp, int flags) | 
|  | { | 
|  | char net[128]; | 
|  | char netdir[128], csname[NETPATHLEN], *slp; | 
|  | char clone[NAMELEN + 12]; | 
|  | char *p; | 
|  | int n; | 
|  | int fd; | 
|  | int rv; | 
|  |  | 
|  | /* go for a standard form net!... */ | 
|  | p = strchr(dest, '!'); | 
|  | if (p == 0) { | 
|  | sprintf(net, "net!%.*s", sizeof(net) - 5, dest); | 
|  | } else { | 
|  | strncpy(net, dest, sizeof(net) - 1); | 
|  | net[sizeof(net) - 1] = 0; | 
|  | } | 
|  |  | 
|  | slp = strrchr(net, '/'); | 
|  | if (slp != 0) { | 
|  | *slp++ = '\0'; | 
|  | strcpy(netdir, net); | 
|  | memmove(net, slp, strlen(slp) + 1); | 
|  | } else | 
|  | strcpy(netdir, "/net"); | 
|  |  | 
|  | // special case because we are so special. | 
|  | // if the first char of the address is a digit, | 
|  | // and the first char of the port is a digit, | 
|  | // skip all this cs stuff. | 
|  | p = strchr(net, '!'); | 
|  | if (p && isdigit(p[1])) { | 
|  | char *q = strchr(&p[1], '!'); | 
|  | if (q && isdigit(q[1])) { | 
|  | *p++ = 0; | 
|  | sprintf(clone, "%s/%s/clone", netdir, net); | 
|  | return call(clone, p, cfdp, dir, local, flags); | 
|  | } | 
|  | } | 
|  | /* call the connection server */ | 
|  | sprintf(csname, "%s/cs", netdir); | 
|  | fd = open(csname, O_RDWR); | 
|  | if (fd < 0) { | 
|  | /* no connection server, don't translate */ | 
|  | p = strchr(net, '!'); | 
|  | *p++ = 0; | 
|  | sprintf(clone, "%s/%s/clone", netdir, net); | 
|  | return call(clone, p, cfdp, dir, local, flags); | 
|  | } | 
|  |  | 
|  | /* | 
|  | *  send dest to connection to translate | 
|  | */ | 
|  | if (write(fd, net, strlen(net)) < 0) { | 
|  | close(fd); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | /* | 
|  | *  loop through each address from the connection server till | 
|  | *  we get one that works. | 
|  | */ | 
|  | rv = -1; | 
|  | lseek(fd, 0, 0); | 
|  | while ((n = read(fd, net, sizeof(net) - 1)) > 0) { | 
|  | net[n] = 0; | 
|  | p = strchr(net, ' '); | 
|  | if (p == 0) | 
|  | continue; | 
|  | *p++ = 0; | 
|  | rv = call(net, p, cfdp, dir, local, flags); | 
|  | if (rv >= 0) | 
|  | break; | 
|  | } | 
|  | close(fd); | 
|  | return rv; | 
|  | } |