xref: /inferno-os/appl/lib/dial.b (revision 8221eca9c386cc14d4cc8e0c7d247a83b11aba18)
1ef054019SCharles.Forsythimplement Dial;
2ef054019SCharles.Forsyth
3ef054019SCharles.Forsythinclude "sys.m";
4ef054019SCharles.Forsyth	sys: Sys;
5ef054019SCharles.Forsyth
6ef054019SCharles.Forsythinclude "dial.m";
7ef054019SCharles.Forsyth
8ef054019SCharles.Forsyth#
9ef054019SCharles.Forsyth# the dialstring is of the form '[/net/]proto!dest'
10ef054019SCharles.Forsyth#
11ef054019SCharles.Forsythdial(addr: string, local: string): ref Connection
12ef054019SCharles.Forsyth{
13ef054019SCharles.Forsyth	if(sys == nil)
14ef054019SCharles.Forsyth		sys = load Sys Sys->PATH;
15ef054019SCharles.Forsyth	(netdir, proto, rem) := dialparse(addr);
16ef054019SCharles.Forsyth	if(netdir != nil)
17ef054019SCharles.Forsyth		return csdial(netdir, proto, rem, local);
18ef054019SCharles.Forsyth
19ef054019SCharles.Forsyth	c := csdial("/net", proto, rem, local);
20ef054019SCharles.Forsyth	if(c != nil)
21ef054019SCharles.Forsyth		return c;
22ef054019SCharles.Forsyth	err := sys->sprint("%r");
23ef054019SCharles.Forsyth	if(lookstr(err, "refused") >= 0)
24ef054019SCharles.Forsyth		return nil;
25ef054019SCharles.Forsyth	c = csdial("/net.alt", proto, rem, local);
26ef054019SCharles.Forsyth	if(c != nil)
27ef054019SCharles.Forsyth		return c;
28ef054019SCharles.Forsyth	# ignore the least precise one
29ef054019SCharles.Forsyth	alterr := sys->sprint("%r");
30ef054019SCharles.Forsyth	if(lookstr(alterr, "translate")>=0 || lookstr(alterr, "does not exist")>=0)
31ef054019SCharles.Forsyth		sys->werrstr(err);
32ef054019SCharles.Forsyth	else
33ef054019SCharles.Forsyth		sys->werrstr(alterr);
34ef054019SCharles.Forsyth	return nil;
35ef054019SCharles.Forsyth}
36ef054019SCharles.Forsyth
37ef054019SCharles.Forsyth#
38ef054019SCharles.Forsyth# ask the connection server to translate
39ef054019SCharles.Forsyth#
40ef054019SCharles.Forsythcsdial(netdir: string, proto: string, rem: string, local: string): ref Connection
41ef054019SCharles.Forsyth{
42ef054019SCharles.Forsyth	fd := sys->open(netdir+"/cs", Sys->ORDWR);
43ef054019SCharles.Forsyth	if(fd == nil){
44ef054019SCharles.Forsyth		# no connection server, don't translate
45ef054019SCharles.Forsyth		return call(netdir+"/"+proto+"/clone", rem, local);
46ef054019SCharles.Forsyth	}
47ef054019SCharles.Forsyth
48ef054019SCharles.Forsyth	if(sys->fprint(fd, "%s!%s", proto, rem) < 0)
49ef054019SCharles.Forsyth		return  nil;
50ef054019SCharles.Forsyth
51ef054019SCharles.Forsyth	# try each recipe until we get one that works
52ef054019SCharles.Forsyth	besterr, err: string;
53ef054019SCharles.Forsyth	sys->seek(fd, big 0, 0);
54ef054019SCharles.Forsyth	for(;;){
55ef054019SCharles.Forsyth		(clonefile, addr) := csread(fd);
56*8221eca9SCharles.Forsyth		if(clonefile == nil)
57ef054019SCharles.Forsyth			break;
58ef054019SCharles.Forsyth		c := call(redir(clonefile, netdir), addr, local);
59ef054019SCharles.Forsyth		if(c != nil)
60ef054019SCharles.Forsyth			return c;
61ef054019SCharles.Forsyth		err = sys->sprint("%r");
62ef054019SCharles.Forsyth		if(lookstr(err, "does not exist") < 0)
63ef054019SCharles.Forsyth			besterr = err;
64ef054019SCharles.Forsyth	}
65ef054019SCharles.Forsyth	if(besterr != nil)
66ef054019SCharles.Forsyth		sys->werrstr(besterr);
67ef054019SCharles.Forsyth	else
68ef054019SCharles.Forsyth		sys->werrstr(err);
69ef054019SCharles.Forsyth	return nil;
70ef054019SCharles.Forsyth}
71ef054019SCharles.Forsyth
72ef054019SCharles.Forsythcall(clonefile: string, dest: string, local: string): ref Connection
73ef054019SCharles.Forsyth{
74ef054019SCharles.Forsyth	(cfd, convdir) := clone(clonefile);
75ef054019SCharles.Forsyth	if(cfd == nil)
76ef054019SCharles.Forsyth		return nil;
77ef054019SCharles.Forsyth
78ef054019SCharles.Forsyth	if(local != nil)
79ef054019SCharles.Forsyth		rv := sys->fprint(cfd, "connect %s %s", dest, local);
80ef054019SCharles.Forsyth	else
81ef054019SCharles.Forsyth		rv = sys->fprint(cfd, "connect %s", dest);
82ef054019SCharles.Forsyth	if(rv < 0)
83ef054019SCharles.Forsyth		return nil;
84ef054019SCharles.Forsyth
85ef054019SCharles.Forsyth	fd := sys->open(convdir+"/data", Sys->ORDWR);
86ef054019SCharles.Forsyth	if(fd == nil)
87ef054019SCharles.Forsyth		return nil;
88ef054019SCharles.Forsyth	return ref Connection(fd, cfd, convdir);
89ef054019SCharles.Forsyth}
90ef054019SCharles.Forsyth
91ef054019SCharles.Forsythclone(clonefile: string): (ref Sys->FD, string)
92ef054019SCharles.Forsyth{
93ef054019SCharles.Forsyth	pdir := parent(clonefile);
94ef054019SCharles.Forsyth	if(pdir == nil){
95ef054019SCharles.Forsyth		sys->werrstr(sys->sprint("bad clone file name: %q", clonefile));
96ef054019SCharles.Forsyth		return (nil, nil);
97ef054019SCharles.Forsyth	}
98ef054019SCharles.Forsyth	cfd := sys->open(clonefile, Sys->ORDWR);
99ef054019SCharles.Forsyth	if(cfd == nil)
100ef054019SCharles.Forsyth		return (nil, nil);
101ef054019SCharles.Forsyth	lno := readchan(cfd);
102ef054019SCharles.Forsyth	if(lno == nil)
103ef054019SCharles.Forsyth		return (nil, nil);
104ef054019SCharles.Forsyth	return (cfd, pdir+"/"+lno);
105ef054019SCharles.Forsyth}
106ef054019SCharles.Forsyth
107ef054019SCharles.Forsythreadchan(cfd: ref Sys->FD): string
108ef054019SCharles.Forsyth{
109ef054019SCharles.Forsyth	buf := array[Sys->NAMEMAX] of byte;
110ef054019SCharles.Forsyth	n := sys->read(cfd, buf, len buf);
111ef054019SCharles.Forsyth	if(n < 0)
112ef054019SCharles.Forsyth		return nil;
113ef054019SCharles.Forsyth	if(n == 0){
114ef054019SCharles.Forsyth		sys->werrstr("empty clone file");
115ef054019SCharles.Forsyth		return nil;
116ef054019SCharles.Forsyth	}
117ef054019SCharles.Forsyth	return string int string buf[0: n];
118ef054019SCharles.Forsyth}
119ef054019SCharles.Forsyth
120ef054019SCharles.Forsythredir(old: string, newdir: string): string
121ef054019SCharles.Forsyth{
122ef054019SCharles.Forsyth	# because cs is in a different name space, replace the mount point
123ef054019SCharles.Forsyth	# assumes the mount point is directory in root (eg, /net/proto/clone)
124ef054019SCharles.Forsyth	if(len old > 1 && old[0] == '/'){
125ef054019SCharles.Forsyth		p := lookc(old[1:], '/');
126ef054019SCharles.Forsyth		if(p >= 0)
127ef054019SCharles.Forsyth			return newdir+"/"+old[1+p+1:];
128ef054019SCharles.Forsyth	}
129ef054019SCharles.Forsyth	return newdir+"/"+old;
130ef054019SCharles.Forsyth}
131ef054019SCharles.Forsyth
132ef054019SCharles.Forsythlookc(s: string, c: int): int
133ef054019SCharles.Forsyth{
134ef054019SCharles.Forsyth	for(i := 0; i < len s; i++)
135ef054019SCharles.Forsyth		if(s[i] == c)
136ef054019SCharles.Forsyth			return i;
137ef054019SCharles.Forsyth	return -1;
138ef054019SCharles.Forsyth}
139ef054019SCharles.Forsyth
140ef054019SCharles.Forsythbackc(s: string, i: int, c: int): int
141ef054019SCharles.Forsyth{
142ef054019SCharles.Forsyth	if(i >= len s)
143ef054019SCharles.Forsyth		return -1;
144ef054019SCharles.Forsyth	while(i >= 0 && s[i] != c)
145ef054019SCharles.Forsyth		i--;
146ef054019SCharles.Forsyth	return i;
147ef054019SCharles.Forsyth}
148ef054019SCharles.Forsyth
149ef054019SCharles.Forsythlookstr(s: string, t: string): int
150ef054019SCharles.Forsyth{
151ef054019SCharles.Forsyth	lt := len t;	# we know it's not zero
152ef054019SCharles.ForsythSearch:
153ef054019SCharles.Forsyth	for(i := 0; i <= len s - lt; i++){
154ef054019SCharles.Forsyth		for(j := 0; j < lt; j++)
155ef054019SCharles.Forsyth			if(s[i+j] != t[j])
156ef054019SCharles.Forsyth				continue Search;
157ef054019SCharles.Forsyth		return i;
158ef054019SCharles.Forsyth	}
159ef054019SCharles.Forsyth	return -1;
160ef054019SCharles.Forsyth}
161ef054019SCharles.Forsyth
162ef054019SCharles.Forsyth#
163ef054019SCharles.Forsyth# [[/netdir/]proto!]remainder
164ef054019SCharles.Forsyth#
165ef054019SCharles.Forsythdialparse(addr: string): (string, string, string)
166ef054019SCharles.Forsyth{
167ef054019SCharles.Forsyth	p := lookc(addr, '!');
168ef054019SCharles.Forsyth	if(p < 0)
169ef054019SCharles.Forsyth		return (nil, "net", addr);
170ef054019SCharles.Forsyth	if(addr[0] != '/' && addr[0] != '#')
171ef054019SCharles.Forsyth		return (nil, addr[0: p], addr[p+1:]);
172ef054019SCharles.Forsyth	p2 := backc(addr, p, '/');
173ef054019SCharles.Forsyth	if(p2 <= 0)
174ef054019SCharles.Forsyth		return (addr[0: p], "net", addr[p+1:]);	# plan 9 returns proto ""
175ef054019SCharles.Forsyth	return (addr[0: p2], addr[p2+1: p], addr[p+1:]);
176ef054019SCharles.Forsyth}
177ef054019SCharles.Forsyth
178ef054019SCharles.Forsyth#
179ef054019SCharles.Forsyth# announce a network service
180ef054019SCharles.Forsyth#
181ef054019SCharles.Forsythannounce(addr: string): ref Connection
182ef054019SCharles.Forsyth{
183ef054019SCharles.Forsyth	if(sys == nil)
184ef054019SCharles.Forsyth		sys = load Sys Sys->PATH;
185ef054019SCharles.Forsyth
186ef054019SCharles.Forsyth	(naddr, clonefile) := nettrans(addr);
187ef054019SCharles.Forsyth	if(naddr == nil)
188ef054019SCharles.Forsyth		return nil;
189ef054019SCharles.Forsyth
190ef054019SCharles.Forsyth	(ctl, convdir) := clone(clonefile);
191ef054019SCharles.Forsyth	if(ctl == nil){
192ef054019SCharles.Forsyth		sys->werrstr(sys->sprint("announce %r"));
193ef054019SCharles.Forsyth		return nil;
194ef054019SCharles.Forsyth	}
195ef054019SCharles.Forsyth
196ef054019SCharles.Forsyth	if(sys->fprint(ctl, "announce %s", naddr) < 0){
197ef054019SCharles.Forsyth		sys->werrstr(sys->sprint("announce writing %s: %r", clonefile));
198ef054019SCharles.Forsyth		return nil;
199ef054019SCharles.Forsyth	}
200ef054019SCharles.Forsyth
201ef054019SCharles.Forsyth	return ref Connection(nil, ctl, convdir);
202ef054019SCharles.Forsyth}
203ef054019SCharles.Forsyth
204ef054019SCharles.Forsyth#
205ef054019SCharles.Forsyth# listen for an incoming call on announced connection
206ef054019SCharles.Forsyth#
207ef054019SCharles.Forsythlisten(ac: ref Connection): ref Connection
208ef054019SCharles.Forsyth{
209ef054019SCharles.Forsyth	if(sys == nil)
210ef054019SCharles.Forsyth		sys = load Sys Sys->PATH;
211ef054019SCharles.Forsyth
212ef054019SCharles.Forsyth	pdir := parent(ac.dir);	# ac.dir should be /netdir/N
213ef054019SCharles.Forsyth	if(pdir == nil){
214ef054019SCharles.Forsyth		sys->werrstr(sys->sprint("listen directory format: %q", ac.dir));
215ef054019SCharles.Forsyth		return nil;
216ef054019SCharles.Forsyth	}
217ef054019SCharles.Forsyth
218ef054019SCharles.Forsyth	ctl := sys->open(ac.dir+"/listen", Sys->ORDWR);
219ef054019SCharles.Forsyth	if(ctl == nil){
220ef054019SCharles.Forsyth		sys->werrstr(sys->sprint("listen opening %s: %r", ac.dir+"/listen"));
221ef054019SCharles.Forsyth		return nil;
222ef054019SCharles.Forsyth	}
223ef054019SCharles.Forsyth
224ef054019SCharles.Forsyth	lno := readchan(ctl);
225ef054019SCharles.Forsyth	if(lno == nil){
226ef054019SCharles.Forsyth		sys->werrstr(sys->sprint("listen reading %s/listen: %r", ac.dir));
227ef054019SCharles.Forsyth		return nil;
228ef054019SCharles.Forsyth	}
229ef054019SCharles.Forsyth	return ref Connection(nil, ctl, pdir+"/"+lno);
230ef054019SCharles.Forsyth
231ef054019SCharles.Forsyth}
232ef054019SCharles.Forsyth
233ef054019SCharles.Forsyth#
234ef054019SCharles.Forsyth# translate an address [[/netdir/]proto!rem] using /netdir/cs
235ef054019SCharles.Forsyth# returning (newaddress, clonefile)
236ef054019SCharles.Forsyth#
237ef054019SCharles.Forsythnettrans(addr: string): (string, string)
238ef054019SCharles.Forsyth{
239ef054019SCharles.Forsyth	(netdir, proto, rem) := dialparse(addr);
240ef054019SCharles.Forsyth	if(proto == nil || proto == "net"){
241ef054019SCharles.Forsyth		sys->werrstr(sys->sprint("bad dial string: %s", addr));
242ef054019SCharles.Forsyth		return (nil, nil);
243ef054019SCharles.Forsyth	}
244ef054019SCharles.Forsyth	if(netdir == nil)
245ef054019SCharles.Forsyth		netdir = "/net";
246ef054019SCharles.Forsyth
247ef054019SCharles.Forsyth	# try to translate using connection server
248ef054019SCharles.Forsyth	fd := sys->open(netdir+"/cs", Sys->ORDWR);
249ef054019SCharles.Forsyth	if(fd == nil){
250ef054019SCharles.Forsyth		# use it untranslated
251ef054019SCharles.Forsyth		if(rem == nil){
252ef054019SCharles.Forsyth			sys->werrstr(sys->sprint("bad dial string: %s", addr));
253ef054019SCharles.Forsyth			return (nil, nil);
254ef054019SCharles.Forsyth		}
255ef054019SCharles.Forsyth		return (rem, netdir+"/"+proto+"/clone");
256ef054019SCharles.Forsyth	}
257ef054019SCharles.Forsyth	if(sys->fprint(fd, "%s!%s", proto, rem) < 0)
258ef054019SCharles.Forsyth		return (nil, nil);
259ef054019SCharles.Forsyth	sys->seek(fd, big 0, 0);
260ef054019SCharles.Forsyth	(clonefile, naddr) := csread(fd);
261ef054019SCharles.Forsyth	if(clonefile == nil)
262ef054019SCharles.Forsyth		return (nil, nil);
263ef054019SCharles.Forsyth
264ef054019SCharles.Forsyth	return (naddr, redir(clonefile, netdir));
265ef054019SCharles.Forsyth}
266ef054019SCharles.Forsyth
267ef054019SCharles.Forsythcsread(fd: ref Sys->FD): (string, string)
268ef054019SCharles.Forsyth{
269ef054019SCharles.Forsyth	buf := array[Sys->NAMEMAX] of byte;
270ef054019SCharles.Forsyth	n := sys->read(fd, buf, len buf);
271ef054019SCharles.Forsyth	if(n < 0)
272ef054019SCharles.Forsyth		return (nil, nil);
273ef054019SCharles.Forsyth	line := string buf[0: n];
274ef054019SCharles.Forsyth	p := lookc(line, ' ');
275ef054019SCharles.Forsyth	if(p < 0)
276ef054019SCharles.Forsyth		return (nil, nil);
277ef054019SCharles.Forsyth	if(p == 0){
278ef054019SCharles.Forsyth		sys->werrstr("cs: no translation");
279ef054019SCharles.Forsyth		return (nil, nil);
280ef054019SCharles.Forsyth	}
281ef054019SCharles.Forsyth	return (line[0:p], line[p+1:]);
282ef054019SCharles.Forsyth}
283ef054019SCharles.Forsyth
284ef054019SCharles.Forsyth#
285ef054019SCharles.Forsyth# accept a call, return an fd to the open data file
286ef054019SCharles.Forsyth#
287ef054019SCharles.Forsythaccept(c: ref Connection): ref Sys->FD
288ef054019SCharles.Forsyth{
289ef054019SCharles.Forsyth	if(sys == nil)
290ef054019SCharles.Forsyth		sys = load Sys Sys->PATH;
291ef054019SCharles.Forsyth	sys->fprint(c.cfd, "accept %s", lastname(c.dir));	# ignore return value, network might not need accepts
292ef054019SCharles.Forsyth	return sys->open(c.dir+"/data", Sys->ORDWR);
293ef054019SCharles.Forsyth}
294ef054019SCharles.Forsyth
295ef054019SCharles.Forsyth#
296ef054019SCharles.Forsyth# reject a call, tell device the reason for the rejection
297ef054019SCharles.Forsyth#
298ef054019SCharles.Forsythreject(c: ref Connection, why: string): int
299ef054019SCharles.Forsyth{
300ef054019SCharles.Forsyth	if(sys == nil)
301ef054019SCharles.Forsyth		sys = load Sys Sys->PATH;
302ef054019SCharles.Forsyth	if(sys->fprint(c.cfd, "reject %s %q", lastname(c.dir), why) < 0)
303ef054019SCharles.Forsyth		return -1;
304ef054019SCharles.Forsyth	return 0;
305ef054019SCharles.Forsyth}
306ef054019SCharles.Forsyth
307ef054019SCharles.Forsythlastname(dir: string): string
308ef054019SCharles.Forsyth{
309ef054019SCharles.Forsyth	p := backc(dir, len dir-1, '/');
310ef054019SCharles.Forsyth	if(p < 0)
311ef054019SCharles.Forsyth		return dir;
312ef054019SCharles.Forsyth	return dir[p+1:];	# N in /net/N
313ef054019SCharles.Forsyth}
314ef054019SCharles.Forsyth
315ef054019SCharles.Forsythparent(dir: string): string
316ef054019SCharles.Forsyth{
317ef054019SCharles.Forsyth	p := backc(dir, len dir-1, '/');
318ef054019SCharles.Forsyth	if(p < 0)
319ef054019SCharles.Forsyth		return nil;
320ef054019SCharles.Forsyth	return dir[0: p];
321ef054019SCharles.Forsyth}
322ef054019SCharles.Forsyth
323ef054019SCharles.Forsythnetmkaddr(addr, net, svc: string): string
324ef054019SCharles.Forsyth{
325ef054019SCharles.Forsyth	if(sys == nil)
326ef054019SCharles.Forsyth		sys = load Sys Sys->PATH;
327ef054019SCharles.Forsyth	if(net == nil)
328ef054019SCharles.Forsyth		net = "net";
329ef054019SCharles.Forsyth	(n, nil) := sys->tokenize(addr, "!");
330ef054019SCharles.Forsyth	if(n <= 1){
331ef054019SCharles.Forsyth		if(svc== nil)
332ef054019SCharles.Forsyth			return sys->sprint("%s!%s", net, addr);
333ef054019SCharles.Forsyth		return sys->sprint("%s!%s!%s", net, addr, svc);
334ef054019SCharles.Forsyth	}
335ef054019SCharles.Forsyth	if(svc == nil || n > 2)
336ef054019SCharles.Forsyth		return addr;
337ef054019SCharles.Forsyth	return sys->sprint("%s!%s", addr, svc);
338ef054019SCharles.Forsyth}
339ef054019SCharles.Forsyth
340ef054019SCharles.Forsythnetinfo(c: ref Connection): ref Conninfo
341ef054019SCharles.Forsyth{
342ef054019SCharles.Forsyth	if(sys == nil)
343ef054019SCharles.Forsyth		sys = load Sys Sys->PATH;
344ef054019SCharles.Forsyth	if((dir := c.dir) == nil){
345ef054019SCharles.Forsyth		if(c.dfd == nil)
346ef054019SCharles.Forsyth			return nil;
347ef054019SCharles.Forsyth		dir = parent(sys->fd2path(c.dfd));
348ef054019SCharles.Forsyth		if(dir == nil)
349ef054019SCharles.Forsyth			return nil;
350ef054019SCharles.Forsyth	}
351ef054019SCharles.Forsyth	ci := ref Conninfo;
352ef054019SCharles.Forsyth	ci.dir = dir;
353ef054019SCharles.Forsyth	ci.root = parent(dir);
354ef054019SCharles.Forsyth	while((p := parent(ci.root)) != nil && p != "/")
355ef054019SCharles.Forsyth		ci.root = p;
356ef054019SCharles.Forsyth	(ok, d) := sys->stat(ci.dir);
357ef054019SCharles.Forsyth	if(ok >= 0)
358ef054019SCharles.Forsyth		ci.spec = sys->sprint("#%c%d", d.dtype, d.dev);
359ef054019SCharles.Forsyth	(ci.lsys, ci.lserv) = getendpoint(ci.dir, "local");
360ef054019SCharles.Forsyth	(ci.rsys, ci.rserv) = getendpoint(ci.dir, "remote");
361ef054019SCharles.Forsyth	p = parent(ci.dir);
362ef054019SCharles.Forsyth	if(p == nil)
363ef054019SCharles.Forsyth		return nil;
364ef054019SCharles.Forsyth	if(len p >= 5 && p[0:5] == "/net/")
365ef054019SCharles.Forsyth		p = p[5:];
366ef054019SCharles.Forsyth	ci.laddr = sys->sprint("%s!%s!%s", p, ci.lsys, ci.lserv);
367ef054019SCharles.Forsyth	ci.raddr = sys->sprint("%s!%s!%s", p, ci.rsys, ci.rserv);
368ef054019SCharles.Forsyth	return ci;
369ef054019SCharles.Forsyth}
370ef054019SCharles.Forsyth
371ef054019SCharles.Forsythgetendpoint(dir: string, file: string): (string, string)
372ef054019SCharles.Forsyth{
373ef054019SCharles.Forsyth	fd := sys->open(dir+"/"+file, Sys->OREAD);
374ef054019SCharles.Forsyth	buf := array[128] of byte;
375ef054019SCharles.Forsyth	if(fd == nil || (n := sys->read(fd, buf, len buf)) <= 0)
376ef054019SCharles.Forsyth		return ("???", "???");	# compatible, but probably poor defaults
377ef054019SCharles.Forsyth	if(n > 0 && buf[n-1] == byte '\n')
378ef054019SCharles.Forsyth		n--;
379ef054019SCharles.Forsyth	s := string buf[0: n];
380ef054019SCharles.Forsyth	p := lookc(s, '!');
381ef054019SCharles.Forsyth	if(p < 0)
382ef054019SCharles.Forsyth		return (s, "???");
383ef054019SCharles.Forsyth	return (s[0:p], s[p+1:]);
384ef054019SCharles.Forsyth}
385