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