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