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