xref: /inferno-os/os/port/dial.c (revision d3641b487cf5cdc46e9b537d30eb37736e5c7b1a)
1 #include	"u.h"
2 #include	"../port/lib.h"
3 #include	"mem.h"
4 #include	"dat.h"
5 #include	"fns.h"
6 #include	"../port/error.h"
7 #include	"kernel.h"
8 
9 typedef struct DS DS;
10 
11 static int	call(char*, char*, DS*);
12 static int	csdial(DS*);
13 static void	_dial_string_parse(char*, DS*);
14 static int	nettrans(char*, char*, int na, char*, int);
15 
16 enum
17 {
18 	Maxstring=	128,
19 	Maxpath=	100
20 };
21 
22 struct DS
23 {
24 	char	buf[Maxstring];			/* dist string */
25 	char	*netdir;
26 	char	*proto;
27 	char	*rem;
28 	char	*local;				/* other args */
29 	char	*dir;
30 	int	*cfdp;
31 };
32 
33 /*
34  *  the dialstring is of the form '[/net/]proto!dest'
35  */
36 int
37 kdial(char *dest, char *local, char *dir, int *cfdp)
38 {
39 	DS ds;
40 	int rv;
41 	char err[ERRMAX], alterr[ERRMAX];
42 
43 	ds.local = local;
44 	ds.dir = dir;
45 	ds.cfdp = cfdp;
46 
47 	_dial_string_parse(dest, &ds);
48 	if(ds.netdir)
49 		return csdial(&ds);
50 
51 	ds.netdir = "/net";
52 	rv = csdial(&ds);
53 	if(rv >= 0)
54 		return rv;
55 
56 	err[0] = 0;
57 	kerrstr(err, sizeof err);
58 	if(strstr(err, "refused") != 0){
59 		kerrstr(err, sizeof err);
60 		return rv;
61 	}
62 
63 	ds.netdir = "/net.alt";
64 	rv = csdial(&ds);
65 	if(rv >= 0)
66 		return rv;
67 
68 	alterr[0] = 0;
69 	kerrstr(alterr, sizeof err);
70 
71 	if(strstr(alterr, "translate") || strstr(alterr, "does not exist"))
72 		kerrstr(err, sizeof err);
73 	else
74 		kerrstr(alterr, sizeof alterr);
75 	return rv;
76 }
77 
78 static int
79 csdial(DS *ds)
80 {
81 	int n, fd, rv;
82 	char *p, buf[Maxstring], clone[Maxpath], err[ERRMAX], besterr[ERRMAX];
83 
84 	/*
85 	 *  open connection server
86 	 */
87 	snprint(buf, sizeof(buf), "%s/cs", ds->netdir);
88 	fd = kopen(buf, ORDWR);
89 	if(fd < 0){
90 		/* no connection server, don't translate */
91 		snprint(clone, sizeof(clone), "%s/%s/clone", ds->netdir, ds->proto);
92 		return call(clone, ds->rem, ds);
93 	}
94 
95 	/*
96 	 *  ask connection server to translate
97 	 */
98 	sprint(buf, "%s!%s", ds->proto, ds->rem);
99 	if(kwrite(fd, buf, strlen(buf)) < 0){
100 		kerrstr(err, sizeof err);
101 		kclose(fd);
102 		kwerrstr("%s (%s)", err, buf);
103 		return -1;
104 	}
105 
106 	/*
107 	 *  loop through each address from the connection server till
108 	 *  we get one that works.
109 	 */
110 	*besterr = 0;
111 	strcpy(err, Egreg);
112 	rv = -1;
113 	kseek(fd, 0, 0);
114 	while((n = kread(fd, buf, sizeof(buf) - 1)) > 0){
115 		buf[n] = 0;
116 		p = strchr(buf, ' ');
117 		if(p == 0)
118 			continue;
119 		*p++ = 0;
120 		rv = call(buf, p, ds);
121 		if(rv >= 0)
122 			break;
123 		err[0] = 0;
124 		kerrstr(err, sizeof err);
125 		if(strstr(err, "does not exist") == 0)
126 			memmove(besterr, err, sizeof besterr);
127 	}
128 	kclose(fd);
129 
130 	if(rv < 0 && *besterr)
131 		kerrstr(besterr, sizeof besterr);
132 	else
133 		kerrstr(err, sizeof err);
134 	return rv;
135 }
136 
137 static int
138 call(char *clone, char *dest, DS *ds)
139 {
140 	int fd, cfd, n;
141 	char name[Maxpath], data[Maxpath], err[ERRMAX], *p;
142 
143 	cfd = kopen(clone, ORDWR);
144 	if(cfd < 0){
145 		kerrstr(err, sizeof err);
146 		kwerrstr("%s (%s)", err, clone);
147 		return -1;
148 	}
149 
150 	/* get directory name */
151 	n = kread(cfd, name, sizeof(name)-1);
152 	if(n < 0){
153 		kerrstr(err, sizeof err);
154 		kclose(cfd);
155 		kwerrstr("read %s: %s", clone, err);
156 		return -1;
157 	}
158 	name[n] = 0;
159 	for(p = name; *p == ' '; p++)
160 		;
161 	sprint(name, "%ld", strtoul(p, 0, 0));
162 	p = strrchr(clone, '/');
163 	*p = 0;
164 	if(ds->dir)
165 		snprint(ds->dir, NETPATHLEN, "%s/%s", clone, name);
166 	snprint(data, sizeof(data), "%s/%s/data", clone, name);
167 
168 	/* connect */
169 	if(ds->local)
170 		snprint(name, sizeof(name), "connect %s %s", dest, ds->local);
171 	else
172 		snprint(name, sizeof(name), "connect %s", dest);
173 	if(kwrite(cfd, name, strlen(name)) < 0){
174 		err[0] = 0;
175 		kerrstr(err, sizeof err);
176 		kclose(cfd);
177 		kwerrstr("%s (%s)", err, name);
178 		return -1;
179 	}
180 
181 	/* open data connection */
182 	fd = kopen(data, ORDWR);
183 	if(fd < 0){
184 		err[0] = 0;
185 		kerrstr(err, sizeof err);
186 		kwerrstr("%s (%s)", err, data);
187 		kclose(cfd);
188 		return -1;
189 	}
190 	if(ds->cfdp)
191 		*ds->cfdp = cfd;
192 	else
193 		kclose(cfd);
194 
195 	return fd;
196 }
197 
198 /*
199  *  parse a dial string
200  */
201 static void
202 _dial_string_parse(char *str, DS *ds)
203 {
204 	char *p, *p2;
205 
206 	strncpy(ds->buf, str, Maxstring);
207 	ds->buf[Maxstring-1] = 0;
208 
209 	p = strchr(ds->buf, '!');
210 	if(p == 0) {
211 		ds->netdir = 0;
212 		ds->proto = "net";
213 		ds->rem = ds->buf;
214 	} else {
215 		if(*ds->buf != '/' && *ds->buf != '#'){
216 			ds->netdir = 0;
217 			ds->proto = ds->buf;
218 		} else {
219 			for(p2 = p; *p2 != '/'; p2--)
220 				;
221 			*p2++ = 0;
222 			ds->netdir = ds->buf;
223 			ds->proto = p2;
224 		}
225 		*p = 0;
226 		ds->rem = p + 1;
227 	}
228 }
229 
230 /*
231  *  announce a network service.
232  */
233 int
234 kannounce(char *addr, char *dir)
235 {
236 	int ctl, n, m;
237 	char buf[NETPATHLEN];
238 	char buf2[Maxpath];
239 	char netdir[NETPATHLEN];
240 	char naddr[Maxpath];
241 	char *cp;
242 
243 	/*
244 	 *  translate the address
245 	 */
246 	if(nettrans(addr, naddr, sizeof(naddr), netdir, sizeof(netdir)) < 0)
247 		return -1;
248 
249 	/*
250 	 * get a control channel
251 	 */
252 	ctl = kopen(netdir, ORDWR);
253 	if(ctl<0)
254 		return -1;
255 	cp = strrchr(netdir, '/');
256 	*cp = 0;
257 
258 	/*
259 	 *  find out which line we have
260 	 */
261 	n = sprint(buf, "%.*s/", sizeof buf, netdir);
262 	m = kread(ctl, &buf[n], sizeof(buf)-n-1);
263 	if(m <= 0){
264 		kclose(ctl);
265 		return -1;
266 	}
267 	buf[n+m] = 0;
268 
269 	/*
270 	 *  make the call
271 	 */
272 	n = snprint(buf2, sizeof buf2, "announce %s", naddr);
273 	if(kwrite(ctl, buf2, n)!=n){
274 		kclose(ctl);
275 		return -1;
276 	}
277 
278 	/*
279 	 *  return directory etc.
280 	 */
281 	if(dir)
282 		strcpy(dir, buf);
283 	return ctl;
284 }
285 
286 /*
287  *  listen for an incoming call
288  */
289 int
290 klisten(char *dir, char *newdir)
291 {
292 	int ctl, n, m;
293 	char buf[NETPATHLEN];
294 	char *cp;
295 
296 	/*
297 	 *  open listen, wait for a call
298 	 */
299 	snprint(buf, sizeof buf, "%s/listen", dir);
300 	ctl = kopen(buf, ORDWR);
301 	if(ctl < 0)
302 		return -1;
303 
304 	/*
305 	 *  find out which line we have
306 	 */
307 	strcpy(buf, dir);
308 	cp = strrchr(buf, '/');
309 	*++cp = 0;
310 	n = cp-buf;
311 	m = kread(ctl, cp, sizeof(buf) - n - 1);
312 	if(m <= 0){
313 		kclose(ctl);
314 		return -1;
315 	}
316 	buf[n+m] = 0;
317 
318 	/*
319 	 *  return directory etc.
320 	 */
321 	if(newdir)
322 		strcpy(newdir, buf);
323 	return ctl;
324 
325 }
326 
327 /*
328  *  perform the identity translation (in case we can't reach cs)
329  */
330 static int
331 identtrans(char *netdir, char *addr, char *naddr, int na, char *file, int nf)
332 {
333 	char proto[Maxpath];
334 	char *p;
335 
336 	USED(nf);
337 
338 	/* parse the protocol */
339 	strncpy(proto, addr, sizeof(proto));
340 	proto[sizeof(proto)-1] = 0;
341 	p = strchr(proto, '!');
342 	if(p)
343 		*p++ = 0;
344 
345 	snprint(file, nf, "%s/%s/clone", netdir, proto);
346 	strncpy(naddr, p, na);
347 	naddr[na-1] = 0;
348 
349 	return 1;
350 }
351 
352 /*
353  *  call up the connection server and get a translation
354  */
355 static int
356 nettrans(char *addr, char *naddr, int na, char *file, int nf)
357 {
358 	int i, fd;
359 	char buf[Maxpath];
360 	char netdir[NETPATHLEN];
361 	char *p, *p2;
362 	long n;
363 
364 	/*
365 	 *  parse, get network directory
366 	 */
367 	p = strchr(addr, '!');
368 	if(p == 0){
369 		kwerrstr("bad dial string: %s", addr);
370 		return -1;
371 	}
372 	if(*addr != '/'){
373 		strcpy(netdir, "/net");
374 	} else {
375 		for(p2 = p; *p2 != '/'; p2--)
376 			;
377 		i = p2 - addr;
378 		if(i == 0 || i >= sizeof(netdir)){
379 			kwerrstr("bad dial string: %s", addr);
380 			return -1;
381 		}
382 		strncpy(netdir, addr, i);
383 		netdir[i] = 0;
384 		addr = p2 + 1;
385 	}
386 
387 	/*
388 	 *  ask the connection server
389 	 */
390 	sprint(buf, "%s/cs", netdir);
391 	fd = kopen(buf, ORDWR);
392 	if(fd < 0)
393 		return identtrans(netdir, addr, naddr, na, file, nf);
394 	if(kwrite(fd, addr, strlen(addr)) < 0){
395 		kclose(fd);
396 		return -1;
397 	}
398 	kseek(fd, 0, 0);
399 	n = kread(fd, buf, sizeof(buf)-1);
400 	kclose(fd);
401 	if(n <= 0)
402 		return -1;
403 	buf[n] = 0;
404 
405 	/*
406 	 *  parse the reply
407 	 */
408 	p = strchr(buf, ' ');
409 	if(p == 0)
410 		return -1;
411 	*p++ = 0;
412 	strncpy(naddr, p, na);
413 	naddr[na-1] = 0;
414 
415 	if(buf[0] == '/'){
416 		p = strchr(buf+1, '/');
417 		if(p == nil)
418 			p = buf;
419 		else
420 			p++;
421 	}
422 	snprint(file, nf, "%s/%s", netdir, p);
423 	return 0;
424 }
425