9c36050ecb08de4450ae2c27e272dc8cfe4b4579
[akaros.git] / user / iplib / dial.c
1 /*
2  * This file is part of the UCB release of Plan 9. It is subject to the license
3  * terms in the LICENSE file found in the top-level directory of this
4  * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
5  * part of the UCB release of Plan 9, including this file, may be copied,
6  * modified, propagated, or distributed except according to the terms contained
7  * in the LICENSE file.
8  */
9 #include <stdlib.h>
10
11 #include <fcntl.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <sys/types.h>
15 #include <unistd.h>
16
17 #define NAMELEN 28
18 #define NETPATHLEN 40
19 static int isdigit(int c)
20 {
21         return ((c >= '0' && c <= '9'));
22 }
23
24 static int call(char *clone, char *dest, int *cfdp, char *dir, char *local,
25                 int flags)
26 {
27         int fd, cfd;
28         int n;
29         char name[3 * NAMELEN + 5];
30         char data[3 * NAMELEN + 10];
31         char *p;
32
33         cfd = open(clone, O_RDWR);
34         if (cfd < 0)
35                 return -1;
36
37         /* get directory name */
38         n = read(cfd, name, sizeof(name) - 1);
39         if (n < 0) {
40                 close(cfd);
41                 return -1;
42         }
43         name[n] = 0;
44         p = strrchr(clone, '/');
45         *p = 0;
46         if (dir)
47                 sprintf(dir, "%.*s/%.*s", 2 * NAMELEN + 1, clone, NAMELEN, name);
48         sprintf(data, "%.*s/%.*s/data", 2 * NAMELEN + 1, clone, NAMELEN, name);
49
50         /* set local side (port number, for example) if we need to */
51         if (local)
52                 sprintf(name, "connect %.*s %.*s", 2 * NAMELEN, dest, NAMELEN, local);
53         else
54                 sprintf(name, "connect %.*s", 2 * NAMELEN, dest);
55         /* connect */
56         if (write(cfd, name, strlen(name)) < 0) {
57                 close(cfd);
58                 return -1;
59         }
60
61         /* open data connection */
62         fd = open(data, O_RDWR | (flags & O_NONBLOCK));
63         if (fd < 0) {
64                 close(cfd);
65                 return -1;
66         }
67         if (cfdp)
68                 *cfdp = cfd;
69         else
70                 close(cfd);
71         return fd;
72 }
73
74 int dial9(char *dest, char *local, char *dir, int *cfdp, int flags)
75 {
76         char net[128];
77         char netdir[128], csname[NETPATHLEN], *slp;
78         char clone[NAMELEN + 12];
79         char *p;
80         int n;
81         int fd;
82         int rv;
83
84         /* go for a standard form net!... */
85         p = strchr(dest, '!');
86         if (p == 0) {
87                 sprintf(net, "net!%.*s", sizeof(net) - 5, dest);
88         } else {
89                 strncpy(net, dest, sizeof(net) - 1);
90                 net[sizeof(net) - 1] = 0;
91         }
92
93         slp = strrchr(net, '/');
94         if (slp != 0) {
95                 *slp++ = '\0';
96                 strcpy(netdir, net);
97                 memmove(net, slp, strlen(slp) + 1);
98         } else
99                 strcpy(netdir, "/net");
100
101         // special case because we are so special.
102         // if the first char of the address is a digit,
103         // and the first char of the port is a digit,
104         // skip all this cs stuff.
105         p = strchr(net, '!');
106         if (p && isdigit(p[1])) {
107                 char *q = strchr(&p[1], '!');
108                 if (q && isdigit(q[1])) {
109                         *p++ = 0;
110                         sprintf(clone, "%s/%s/clone", netdir, net);
111                         return call(clone, p, cfdp, dir, local, flags);
112                 }
113         }
114         /* call the connection server */
115         sprintf(csname, "%s/cs", netdir);
116         fd = open(csname, O_RDWR);
117         if (fd < 0) {
118                 /* no connection server, don't translate */
119                 p = strchr(net, '!');
120                 *p++ = 0;
121                 sprintf(clone, "%s/%s/clone", netdir, net);
122                 return call(clone, p, cfdp, dir, local, flags);
123         }
124
125         /*
126          *  send dest to connection to translate
127          */
128         if (write(fd, net, strlen(net)) < 0) {
129                 close(fd);
130                 return -1;
131         }
132
133         /*
134          *  loop through each address from the connection server till
135          *  we get one that works.
136          */
137         rv = -1;
138         lseek(fd, 0, 0);
139         while ((n = read(fd, net, sizeof(net) - 1)) > 0) {
140                 net[n] = 0;
141                 p = strchr(net, ' ');
142                 if (p == 0)
143                         continue;
144                 *p++ = 0;
145                 rv = call(net, p, cfdp, dir, local, flags);
146                 if (rv >= 0)
147                         break;
148         }
149         close(fd);
150         return rv;
151 }