History

20071128-2330

Charles.Forsyth committed 18 years ago

Commit 626b4d81 parent 06dd0898 files · +753 −-1Browse files

Unified · Split

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

Binary file not shown.

lib/proto/inferno+10−0
@@ -706,7 +706,9 @@ appl · 705 unmodified lines
706706 echo.b
707707 expr.b
708708 file2chan.b
709+ mload.b
709710 mkfile
711+ mpexpr.b
710712 regex.b
711713 sexprs.b
712714 sh.b
@@ -963,6 +965,7 @@ appl · 250 unmodified lines
963965 deflate.b
964966 devpointer.b
965967 dhcpclient.b
968+ dial.b
966969 dialog.b
967970 dict.b
968971 dis.b
@@ -1091,6 +1094,7 @@ appl · 122 unmodified lines
10911094 string.b
10921095 strinttab.b
10931096 styx.b
1097+ styxflush.b
10941098 styxlib.b
10951099 styxservers.b
10961100 tables.b
@@ -1588,6 +1592,7 @@ dis · 491 unmodified lines
15881592 deflate.dis
15891593 devpointer.dis
15901594 dhcpclient.dis
1595+ dial.dis
15911596 dialog.dis
15921597 dict.dis
15931598 dis.dis
@@ -1686,6 +1691,7 @@ dis · 92 unmodified lines
16861691 styx.dis
16871692 styxconv
16881693 +
1694+ styxflush.dis
16891695 styxlib.dis
16901696 styxpersist.dis
16911697 styxservers.dis
@@ -2191,6 +2197,8 @@ mkfiles · 499 unmodified lines
21912197 *
21922198 mnt
21932199 *
2200+ spki
2201+ keys
21942202 module
21952203 NOTICE
21962204 alphabet.m
@@ -2221,6 +2229,7 @@ module · 24 unmodified lines
22212229 debug.m
22222230 devpointer.m
22232231 dhcp.m
2232+ dial.m
22242233 dialog.m
22252234 dict.m
22262235 dis.m
@@ -2326,6 +2335,7 @@ module · 99 unmodified lines
23262335 strinttab.m
23272336 styx.m
23282337 styxconv.m
2338+ styxflush.m
23292339 styxlib.m
23302340 styxpersist.m
23312341 styxservers.m
man/1/INDEX+4−0
@@ -183,6 +183,7 @@ csv sh-csv · 182 unmodified lines
183183 getcsv sh-csv
184184 sh-csv sh-csv
185185 expr sh-expr
186+mpexpr sh-expr
186187 ntest sh-expr
187188 sh-expr sh-expr
188189 file2chan sh-file2chan
@@ -194,6 +195,9 @@ rread sh-file2chan · 5 unmodified lines
194195 rreadone sh-file2chan
195196 rwrite sh-file2chan
196197 sh-file2chan sh-file2chan
198+mload sh-mload
199+munload sh-mload
200+sh-mload sh-mload
197201 match sh-regex
198202 re sh-regex
199203 sh-regex sh-regex
man/2/INDEX+8−0
@@ -44,6 +44,13 @@ dhcp dhcpclient · 43 unmodified lines
4444 dhcpclient dhcpclient
4545 lease dhcpclient
4646 removecfg dhcpclient
47+accept dial
48+announce dial
49+dial dial
50+listen dial
51+netinfo dial
52+netmkaddr dial
53+reject dial
4754 dialog dialog
4855 getstring dialog
4956 prompt dialog
@@ -387,6 +394,7 @@ styx styx · 337 unmodified lines
387394 tmsg styx
388395 unpackdir styx
389396 styxconv styxconv
397+styxflush styxflush
390398 styxpersist styxpersist
391399 styxservers styxservers
392400 nametree styxservers-nametree
man/2/dial+312−0
@@ -0,0 +1,312 @@
1+.TH DIAL 2
2+.SH NAME
3+Dial: accept, announce, dial, listen, netinfo, netmkaddr, reject \- make network connections
4+.SH SYNOPSIS
5+.EX
6+include "sys.m";
7+dial := load Dial Dial->PATH;
8+
9+Connection: adt
10+{
11+ dfd: ref FD; # data file
12+ cfd: ref FD; # control file
13+ dir: string; # pathname of line directory
14+};
15+
16+announce: fn(addr: string): ref Connection;
17+dial: fn(addr, local: string): ref Connection;
18+listen: fn(c: ref Connection): ref Connection;
19+accept: fn(c: ref Connection): ref Sys->FD;
20+reject: fn(c: ref Connection, why: string);
21+
22+netmkaddr: fn(net, host, svc: string): string;
23+
24+Conninfo: adt
25+{
26+ dir: string; # connection directory
27+ root: string; # network mount point
28+ spec: string; # its binding spec
29+ lsys: string; # local host address
30+ lserv: string; # local service
31+ rsys: string; # remote host address
32+ rserv: string; # remote service
33+ laddr: string; # local address in dial form
34+ raddr: string; # remote address in dial form
35+};
36+
37+netinfo: fn(c: ref Connection): ref Conninfo;
38+.EE
39+.SH DESCRIPTION
40+.B Dial
41+establishes network connections.
42+The description below uses the following definitions:
43+.TF network
44+.PD
45+.TP
46+.I addr
47+is a network address in one of the following forms:
48+.br
49+.IP
50+.IB network ! netaddr ! service\f1
51+.br
52+.IB network ! netaddr\f1
53+.br
54+.IR netaddr
55+.TP
56+.I network
57+Any directory listed in
58+.B /net
59+(eg,
60+.BR tcp ),
61+or the special token,
62+.BR net .
63+The special name
64+.B net
65+stands for any network that connects
66+the current host and
67+.IR netaddr .
68+A network name can be preceded by the full path name of a directory
69+of networks, using the form
70+.I /dir/network
71+(eg,
72+.BR /net.alt/tcp ).
73+.TP
74+.I netaddr
75+A host name, a domain name, a network address,
76+or a meta-name of the form
77+.BI $ attribute\f1,
78+which
79+is replaced by
80+.I value
81+from the corresponding attribute-value pair
82+in the connection server data base (see
83+.IR db (6)).
84+.PP
85+The functions
86+.B dial
87+and
88+.B announce
89+translate a given
90+.I addr
91+to an actual network address using
92+the connection server
93+.IR cs (8).
94+If a logical name
95+.I addr
96+corresponds to several network addresses,
97+for instance if a destination machine has several interfaces,
98+.I cs
99+will return them all;
100+.B dial
101+or
102+.B announce
103+will try each in turn until one works.
104+In particular, if
105+.I addr
106+is
107+.BR net ,
108+.I cs
109+will return addresses on
110+all networks that are common to source and destination.
111+The translation procedure accesses
112+.I cs
113+using its interface file
114+.BR cs ,
115+which is sought as follows:
116+first, in an explicit directory
117+.BI / dir
118+if one was given in
119+.IR network ;
120+second, in the standard directory
121+.BR /net ;
122+and finally in the directory
123+.BR /net.alt
124+.RB ( dial
125+only).
126+If the connection server cannot be found,
127+the
128+.I addr
129+is used as-is.
130+.PP
131+If a connection attempt is successful, the
132+.B dir
133+member of the resulting
134+.B Connection
135+will be
136+the path name of a
137+.I line directory
138+that has files for accessing the connection.
139+One line directory exists for each possible connection.
140+The
141+.B data
142+file in the line directory is opened to
143+make a connection, and read and written to communicate with the destination.
144+The
145+.B ctl
146+file in the line directory can be used to send commands to the line.
147+See
148+.IR ip (3)
149+for messages that can be written to the
150+.B ctl
151+file.
152+The last close of both
153+.B data
154+and
155+.B ctl
156+file will close the connection.
157+The
158+.B remote
159+file in the line directory contains the address called; the file
160+.B local
161+contains the local address assigned.
162+.PP
163+The function
164+.B dial
165+calls destination
166+.I addr
167+on a multiplexed network.
168+If the connection server returns several possible locations for
169+.IR addr ,
170+.B dial
171+tries each in turn, until a connection is made,
172+or no address remains to be tried.
173+.B Dial
174+returns a reference to a
175+.B Connection
176+value containing a string
177+.B dir
178+that names the conversation directory for the connection,
179+a file descriptor
180+.B dfd
181+open for reading and writing the
182+.B data
183+file in that directory, and
184+a file descriptor
185+.B cfd
186+open for reading and writing the directory's
187+.B ctl
188+file.
189+If
190+.IR local
191+is non-empty, and the network allows the local address to be set,
192+as is the case with UDP and TCP port numbers,
193+the local address will be set to
194+.IR local .
195+.PP
196+.B Announce
197+and
198+.B listen
199+are the complements of
200+.BR dial .
201+.B Announce
202+establishes a network name to which incoming calls can be made.
203+In
204+.IR addr ,
205+.I netaddr
206+gives the name or address of one of the local host's interfaces on which to listen for
207+calls to the given
208+.IR service ;
209+it can be
210+.B *
211+to listen for calls on any interface on
212+.IR network .
213+.B Announce
214+returns a reference to a
215+.B Connection
216+value in which only the
217+.B cfd
218+descriptor is open, on the control file representing the announcement.
219+.B Listen
220+takes as its only argument a reference to the
221+.B Connection
222+returned by a successful call to
223+.BR announce .
224+When a call is received,
225+.B listen
226+returns a reference to a new
227+.B Connection
228+value that refers to the conversation directory for the incoming call;
229+only the
230+.B cfd
231+descriptor is open.
232+That call can be accepted or rejected.
233+Use
234+.B accept
235+to obtain a file descriptor for the data file for the conversation.
236+Use
237+.B reject
238+to reject the incoming call; some networks will also tell the caller the reason
239+.IR why .
240+.PP
241+Given a
242+.BR Connection ,
243+.B netinfo
244+returns a reference to a
245+.B Conninfo
246+value that gives details about the connection and its network.
247+.SH EXAMPLES
248+.PP
249+Make a call and return an open file descriptor to
250+use for communications:
251+.IP
252+.EX
253+callkremvax(): ref Sys->FD
254+{
255+ c := dial->dial("tcp!kremvax!80", nil);
256+ if(c == nil)
257+ return nil;
258+ return c.dfd;
259+}
260+.EE
261+.PP
262+Call the local certificate signer:
263+.IP
264+.EX
265+dialsigner(service: string): ref Sys->FD
266+{
267+ c := dial->dial("net!$SIGNER!inflogin", nil);
268+ if(c == nil)
269+ return nil;
270+ return c.dfd;
271+}
272+.EE
273+.PP
274+Listen for incoming calls.
275+.IP
276+.EX
277+listener()
278+{
279+ ac := dial->announce("tcp!*!9995");
280+ if(ac == nil){
281+ sys->print("can't announce: %r\n");
282+ exit;
283+ }
284+ for(;;){
285+ lc := dial->listen(ac);
286+ if(lc == nil){
287+ sys->print("listen: %r\n");
288+ exit;
289+ }
290+ sys->print("incoming: %s\n", hd ctext(lc));
291+ spawn client(lc);
292+ }
293+}
294+
295+client(c: ref Connection)
296+{
297+ dfd := dial->accept(c);
298+ if(dfd == nil){
299+ sys->print("%s: can't accept: %r\n", c.dir);
300+ exit;
301+ }
302+ buf := array[Sys->ATOMICIO] of byte;
303+ while((n := sys->read(dfd, buf, len buf)) > 0)
304+ sys->write(dfd, buf, n);
305+}
306+.EE
307+.SH SOURCE
308+.B /appl/lib/dial.b
309+.SH DIAGNOSTICS
310+The integer valued functions return 0 on success and -1 on error;
311+functions returning a reference return nil on error.
312+In those cases the system error string is set.
module/dial.m+34−0
@@ -0,0 +1,34 @@
1+Dial: module
2+{
3+ PATH: con "/dis/lib/dial.dis";
4+
5+ Connection: adt
6+ {
7+ dfd: ref Sys->FD;
8+ cfd: ref Sys->FD;
9+ dir: string;
10+ };
11+
12+ Conninfo: adt
13+ {
14+ dir: string;
15+ root: string;
16+ spec: string;
17+ lsys: string;
18+ lserv: string;
19+ rsys: string;
20+ rserv: string;
21+ laddr: string;
22+ raddr: string;
23+ };
24+
25+ announce: fn(addr: string): ref Connection;
26+ dial: fn(addr, local: string): ref Connection;
27+ listen: fn(c: ref Connection): ref Connection;
28+ accept: fn(c: ref Connection): ref Sys->FD;
29+ reject: fn(c: ref Connection, why: string): int;
30+# parse: fn(addr: string): (string, string, string);
31+
32+ netmkaddr: fn(addr, net, svc: string): string;
33+ netinfo: fn(c: ref Connection): ref Conninfo;
34+};