1 #include <u.h>
2 #include <libc.h>
3
4 typedef struct DS DS;
5
6 static int call(char*, char*, DS*);
7 static int csdial(DS*);
8 static void _dial_string_parse(char*, DS*);
9
10 enum
11 {
12 Maxstring = 128,
13 Maxpath = 256,
14 };
15
16 struct DS {
17 /* dist string */
18 char buf[Maxstring];
19 char *netdir;
20 char *proto;
21 char *rem;
22
23 /* other args */
24 char *local;
25 char *dir;
26 int *cfdp;
27 };
28
29
30 /*
31 * the dialstring is of the form '[/net/]proto!dest'
32 */
33 int
dial(char * dest,char * local,char * dir,int * cfdp)34 dial(char *dest, char *local, char *dir, int *cfdp)
35 {
36 DS ds;
37 int rv;
38 char err[ERRMAX], alterr[ERRMAX];
39
40 ds.local = local;
41 ds.dir = dir;
42 ds.cfdp = cfdp;
43
44 _dial_string_parse(dest, &ds);
45 if(ds.netdir)
46 return csdial(&ds);
47
48 ds.netdir = "/net";
49 rv = csdial(&ds);
50 if(rv >= 0)
51 return rv;
52 err[0] = '\0';
53 errstr(err, sizeof err);
54 if(strstr(err, "refused") != 0){
55 werrstr("%s", err);
56 return rv;
57 }
58 ds.netdir = "/net.alt";
59 rv = csdial(&ds);
60 if(rv >= 0)
61 return rv;
62
63 alterr[0] = 0;
64 errstr(alterr, sizeof alterr);
65 if(strstr(alterr, "translate") || strstr(alterr, "does not exist"))
66 werrstr("%s", err);
67 else
68 werrstr("%s", alterr);
69 return rv;
70 }
71
72 static int
csdial(DS * ds)73 csdial(DS *ds)
74 {
75 int n, fd, rv;
76 char *p, buf[Maxstring], clone[Maxpath], err[ERRMAX], besterr[ERRMAX];
77
78 /*
79 * open connection server
80 */
81 snprint(buf, sizeof(buf), "%s/cs", ds->netdir);
82 fd = open(buf, ORDWR);
83 if(fd < 0){
84 /* no connection server, don't translate */
85 snprint(clone, sizeof(clone), "%s/%s/clone", ds->netdir, ds->proto);
86 return call(clone, ds->rem, ds);
87 }
88
89 /*
90 * ask connection server to translate
91 */
92 snprint(buf, sizeof(buf), "%s!%s", ds->proto, ds->rem);
93 if(write(fd, buf, strlen(buf)) < 0){
94 close(fd);
95 return -1;
96 }
97
98 /*
99 * loop through each address from the connection server till
100 * we get one that works.
101 */
102 *besterr = 0;
103 rv = -1;
104 seek(fd, 0, 0);
105 strcpy(err, "cs gave empty translation list");
106 while((n = read(fd, buf, sizeof(buf) - 1)) > 0){
107 buf[n] = 0;
108 p = strchr(buf, ' ');
109 if(p == 0)
110 continue;
111 *p++ = 0;
112 rv = call(buf, p, ds);
113 if(rv >= 0)
114 break;
115 err[0] = '\0';
116 errstr(err, sizeof err);
117 if(strstr(err, "does not exist") == 0)
118 strcpy(besterr, err);
119 }
120 close(fd);
121
122 if(rv < 0 && *besterr)
123 werrstr("%s", besterr);
124 else
125 werrstr("%s", err);
126 return rv;
127 }
128
129 static int
call(char * clone,char * dest,DS * ds)130 call(char *clone, char *dest, DS *ds)
131 {
132 int fd, cfd, n;
133 char name[Maxpath], data[Maxpath], *p;
134
135 cfd = open(clone, ORDWR);
136 if(cfd < 0)
137 return -1;
138
139 /* get directory name */
140 n = read(cfd, name, sizeof(name)-1);
141 if(n < 0){
142 close(cfd);
143 return -1;
144 }
145 name[n] = 0;
146 for(p = name; *p == ' '; p++)
147 ;
148 snprint(name, sizeof(name), "%ld", strtoul(p, 0, 0));
149 p = strrchr(clone, '/');
150 *p = 0;
151 if(ds->dir)
152 snprint(ds->dir, NETPATHLEN, "%s/%s", clone, name);
153 snprint(data, sizeof(data), "%s/%s/data", clone, name);
154
155 /* connect */
156 if(ds->local)
157 snprint(name, sizeof(name), "connect %s %s", dest, ds->local);
158 else
159 snprint(name, sizeof(name), "connect %s", dest);
160 if(write(cfd, name, strlen(name)) < 0){
161 close(cfd);
162 return -1;
163 }
164
165 /* open data connection */
166 fd = open(data, ORDWR);
167 if(fd < 0){
168 print("open %s: %r\n", data);
169 close(cfd);
170 return -1;
171 }
172 if(ds->cfdp)
173 *ds->cfdp = cfd;
174 else
175 close(cfd);
176 return fd;
177 }
178
179 /*
180 * parse a dial string
181 */
182 static void
_dial_string_parse(char * str,DS * ds)183 _dial_string_parse(char *str, DS *ds)
184 {
185 char *p, *p2;
186
187 strncpy(ds->buf, str, Maxstring);
188 ds->buf[Maxstring-1] = 0;
189
190 p = strchr(ds->buf, '!');
191 if(p == 0) {
192 ds->netdir = 0;
193 ds->proto = "net";
194 ds->rem = ds->buf;
195 } else {
196 if(*ds->buf != '/' && *ds->buf != '#'){
197 ds->netdir = 0;
198 ds->proto = ds->buf;
199 } else {
200 for(p2 = p; *p2 != '/'; p2--)
201 ;
202 *p2++ = 0;
203 ds->netdir = ds->buf;
204 ds->proto = p2;
205 }
206 *p = 0;
207 ds->rem = p + 1;
208 }
209 }
210