| /* |
| * 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; |
| } |