Unified · Split
| @@ -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 | +} | |
| @@ -113,6 +113,7 @@ TARG=\ · 112 unmodified lines | ||
| 113 | 113 | string.dis\ |
| 114 | 114 | strinttab.dis\ |
| 115 | 115 | styx.dis\ |
| 116 | + styxflush.dis\ | |
| 116 | 117 | styxlib.dis\ |
| 117 | 118 | styxpersist.dis\ |
| 118 | 119 | styxservers.dis\ |
| @@ -234,3 +235,4 @@ csv.dis: $ROOT/module/csv.m · 115 unmodified lines | ||
| 234 | 235 | json.dis: $ROOT/module/json.m |
| 235 | 236 | lists.dis: $ROOT/module/lists.m |
| 236 | 237 | vac.dis: $ROOT/module/vac.m $ROOT/module/venti.m |
| 238 | +dial.dis: $ROOT/module/dial.m | |
Binary file not shown.
| @@ -706,7 +706,9 @@ appl · 705 unmodified lines | ||
| 706 | 706 | echo.b |
| 707 | 707 | expr.b |
| 708 | 708 | file2chan.b |
| 709 | + mload.b | |
| 709 | 710 | mkfile |
| 711 | + mpexpr.b | |
| 710 | 712 | regex.b |
| 711 | 713 | sexprs.b |
| 712 | 714 | sh.b |
| @@ -963,6 +965,7 @@ appl · 250 unmodified lines | ||
| 963 | 965 | deflate.b |
| 964 | 966 | devpointer.b |
| 965 | 967 | dhcpclient.b |
| 968 | + dial.b | |
| 966 | 969 | dialog.b |
| 967 | 970 | dict.b |
| 968 | 971 | dis.b |
| @@ -1091,6 +1094,7 @@ appl · 122 unmodified lines | ||
| 1091 | 1094 | string.b |
| 1092 | 1095 | strinttab.b |
| 1093 | 1096 | styx.b |
| 1097 | + styxflush.b | |
| 1094 | 1098 | styxlib.b |
| 1095 | 1099 | styxservers.b |
| 1096 | 1100 | tables.b |
| @@ -1588,6 +1592,7 @@ dis · 491 unmodified lines | ||
| 1588 | 1592 | deflate.dis |
| 1589 | 1593 | devpointer.dis |
| 1590 | 1594 | dhcpclient.dis |
| 1595 | + dial.dis | |
| 1591 | 1596 | dialog.dis |
| 1592 | 1597 | dict.dis |
| 1593 | 1598 | dis.dis |
| @@ -1686,6 +1691,7 @@ dis · 92 unmodified lines | ||
| 1686 | 1691 | styx.dis |
| 1687 | 1692 | styxconv |
| 1688 | 1693 | + |
| 1694 | + styxflush.dis | |
| 1689 | 1695 | styxlib.dis |
| 1690 | 1696 | styxpersist.dis |
| 1691 | 1697 | styxservers.dis |
| @@ -2191,6 +2197,8 @@ mkfiles · 499 unmodified lines | ||
| 2191 | 2197 | * |
| 2192 | 2198 | mnt |
| 2193 | 2199 | * |
| 2200 | + spki | |
| 2201 | + keys | |
| 2194 | 2202 | module |
| 2195 | 2203 | NOTICE |
| 2196 | 2204 | alphabet.m |
| @@ -2221,6 +2229,7 @@ module · 24 unmodified lines | ||
| 2221 | 2229 | debug.m |
| 2222 | 2230 | devpointer.m |
| 2223 | 2231 | dhcp.m |
| 2232 | + dial.m | |
| 2224 | 2233 | dialog.m |
| 2225 | 2234 | dict.m |
| 2226 | 2235 | dis.m |
| @@ -2326,6 +2335,7 @@ module · 99 unmodified lines | ||
| 2326 | 2335 | strinttab.m |
| 2327 | 2336 | styx.m |
| 2328 | 2337 | styxconv.m |
| 2338 | + styxflush.m | |
| 2329 | 2339 | styxlib.m |
| 2330 | 2340 | styxpersist.m |
| 2331 | 2341 | styxservers.m |
| @@ -183,6 +183,7 @@ csv sh-csv · 182 unmodified lines | ||
| 183 | 183 | getcsv sh-csv |
| 184 | 184 | sh-csv sh-csv |
| 185 | 185 | expr sh-expr |
| 186 | +mpexpr sh-expr | |
| 186 | 187 | ntest sh-expr |
| 187 | 188 | sh-expr sh-expr |
| 188 | 189 | file2chan sh-file2chan |
| @@ -194,6 +195,9 @@ rread sh-file2chan · 5 unmodified lines | ||
| 194 | 195 | rreadone sh-file2chan |
| 195 | 196 | rwrite sh-file2chan |
| 196 | 197 | sh-file2chan sh-file2chan |
| 198 | +mload sh-mload | |
| 199 | +munload sh-mload | |
| 200 | +sh-mload sh-mload | |
| 197 | 201 | match sh-regex |
| 198 | 202 | re sh-regex |
| 199 | 203 | sh-regex sh-regex |
| @@ -44,6 +44,13 @@ dhcp dhcpclient · 43 unmodified lines | ||
| 44 | 44 | dhcpclient dhcpclient |
| 45 | 45 | lease dhcpclient |
| 46 | 46 | removecfg dhcpclient |
| 47 | +accept dial | |
| 48 | +announce dial | |
| 49 | +dial dial | |
| 50 | +listen dial | |
| 51 | +netinfo dial | |
| 52 | +netmkaddr dial | |
| 53 | +reject dial | |
| 47 | 54 | dialog dialog |
| 48 | 55 | getstring dialog |
| 49 | 56 | prompt dialog |
| @@ -387,6 +394,7 @@ styx styx · 337 unmodified lines | ||
| 387 | 394 | tmsg styx |
| 388 | 395 | unpackdir styx |
| 389 | 396 | styxconv styxconv |
| 397 | +styxflush styxflush | |
| 390 | 398 | styxpersist styxpersist |
| 391 | 399 | styxservers styxservers |
| 392 | 400 | nametree styxservers-nametree |
| @@ -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. | |
| @@ -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 | +}; | |