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