137da2899SCharles.Forsythimplement Virgil; 237da2899SCharles.Forsyth 337da2899SCharles.Forsythinclude "sys.m"; 437da2899SCharles.Forsyth sys: Sys; 537da2899SCharles.Forsythinclude "string.m"; 637da2899SCharles.Forsythinclude "keyring.m"; 737da2899SCharles.Forsythinclude "draw.m"; 8*fbc1184cSCharles Forsythinclude "dial.m"; 9*fbc1184cSCharles Forsyth dial: Dial; 1037da2899SCharles.Forsythinclude "security.m"; 1137da2899SCharles.Forsythinclude "ip.m"; 1237da2899SCharles.Forsyth ip: IP; 1337da2899SCharles.Forsyth IPaddr, Udphdr: import ip; 1437da2899SCharles.Forsyth 1537da2899SCharles.Forsythstderr: ref Sys->FD; 1637da2899SCharles.Forsythdone: int; 17504229f8SCharles.ForsythUdphdrsize: con IP->Udphdrlen; 1837da2899SCharles.ForsythVirgilport: con 2202; 1937da2899SCharles.Forsyth 2037da2899SCharles.Forsyth# 2137da2899SCharles.Forsyth# this module is very udp dependent. it shouldn't be. -- presotto 2237da2899SCharles.Forsyth# Call with first element of argv an arbitrary string, which is 2337da2899SCharles.Forsyth# discarded here. argv must also contain at least a question. 2437da2899SCharles.Forsyth# 2537da2899SCharles.Forsythvirgil(argv: list of string): string 2637da2899SCharles.Forsyth{ 2737da2899SCharles.Forsyth s,question,reply,r : string; 2837da2899SCharles.Forsyth timerpid, readerpid: int; 2937da2899SCharles.Forsyth 3037da2899SCharles.Forsyth if (argv == nil || tl argv == nil || hd (tl argv) == nil) 3137da2899SCharles.Forsyth return nil; 3237da2899SCharles.Forsyth done = 0; 3337da2899SCharles.Forsyth sys = load Sys Sys->PATH; 34*fbc1184cSCharles Forsyth dial = load Dial Dial->PATH; 35*fbc1184cSCharles Forsyth if(dial == nil){ 36*fbc1184cSCharles Forsyth cantload(Dial->PATH); 37*fbc1184cSCharles Forsyth return nil; 38*fbc1184cSCharles Forsyth } 3937da2899SCharles.Forsyth str := load String String->PATH; 4037da2899SCharles.Forsyth if(str == nil){ 4137da2899SCharles.Forsyth cantload(String->PATH); 4237da2899SCharles.Forsyth return nil; 4337da2899SCharles.Forsyth } 4437da2899SCharles.Forsyth ip = load IP IP->PATH; 4537da2899SCharles.Forsyth if(ip == nil){ 4637da2899SCharles.Forsyth cantload(IP->PATH); 4737da2899SCharles.Forsyth return nil; 4837da2899SCharles.Forsyth } 4937da2899SCharles.Forsyth ip->init(); 5037da2899SCharles.Forsyth stderr = sys->fildes(2); 5137da2899SCharles.Forsyth 5237da2899SCharles.Forsyth # We preserve the convention that the first arg is not an option. 5337da2899SCharles.Forsyth # Undocumented '-v address' option allows passing in address 5437da2899SCharles.Forsyth # of virgild, circumventing broadcast. Used for development, 5537da2899SCharles.Forsyth # to avoid pestering servers on network. 5637da2899SCharles.Forsyth dest := ip->v4bcast; 5737da2899SCharles.Forsyth argv = tl argv; 5837da2899SCharles.Forsyth s = hd argv; 5937da2899SCharles.Forsyth if(s[0] == '-') { 6037da2899SCharles.Forsyth if(s[1] != 'v') 6137da2899SCharles.Forsyth return nil; 6237da2899SCharles.Forsyth argv = tl argv; 6337da2899SCharles.Forsyth if (argv == nil) 6437da2899SCharles.Forsyth return nil; 6537da2899SCharles.Forsyth s = hd argv; 6637da2899SCharles.Forsyth ok: int; 6737da2899SCharles.Forsyth (ok, dest) = IPaddr.parse(s); 6837da2899SCharles.Forsyth if(ok < 0){ 6937da2899SCharles.Forsyth sys->fprint(stderr, "virgil: invalid IP address %s\n", s); 7037da2899SCharles.Forsyth return nil; 7137da2899SCharles.Forsyth } 7237da2899SCharles.Forsyth argv = tl argv; 7337da2899SCharles.Forsyth } 7437da2899SCharles.Forsyth 7537da2899SCharles.Forsyth # Is there a question? 7637da2899SCharles.Forsyth if (argv == nil) 7737da2899SCharles.Forsyth return nil; 7837da2899SCharles.Forsyth question = hd argv; 7937da2899SCharles.Forsyth 80*fbc1184cSCharles Forsyth c := dial->announce("udp!*!0"); 81*fbc1184cSCharles Forsyth if(c == nil) 8237da2899SCharles.Forsyth return nil; 8337da2899SCharles.Forsyth if(sys->fprint(c.cfd, "headers") < 0) 8437da2899SCharles.Forsyth return nil; 8537da2899SCharles.Forsyth c.dfd = sys->open(c.dir+"/data", sys->ORDWR); 8637da2899SCharles.Forsyth if(c.dfd == nil) 8737da2899SCharles.Forsyth return nil; 8837da2899SCharles.Forsyth 8937da2899SCharles.Forsyth readerchan := chan of string; 9037da2899SCharles.Forsyth timerchan := chan of int; 9137da2899SCharles.Forsyth readerpidchan := chan of int; 9237da2899SCharles.Forsyth 9337da2899SCharles.Forsyth spawn timer(timerchan); 9437da2899SCharles.Forsyth timerpid = <-timerchan; 9537da2899SCharles.Forsyth spawn reader(c.dfd, readerchan, readerpidchan); 9637da2899SCharles.Forsyth readerpid = <-readerpidchan; 9737da2899SCharles.Forsyth 9837da2899SCharles.Forsyth question = getid() + "?" + question; 9937da2899SCharles.Forsyth qbuf := array of byte question; 10037da2899SCharles.Forsyth hdr := Udphdr.new(); 10137da2899SCharles.Forsyth hdr.raddr = dest; 10237da2899SCharles.Forsyth hdr.rport = Virgilport; 10337da2899SCharles.Forsyth buf := array[Udphdrsize + len qbuf] of byte; 10437da2899SCharles.Forsyth buf[Udphdrsize:] = qbuf; 10537da2899SCharles.Forsyth hdr.pack(buf, Udphdrsize); 10637da2899SCharles.Forsyth for(tries := 0; tries < 5; ){ 10737da2899SCharles.Forsyth if(sys->write(c.dfd, buf, len buf) < 0) 10837da2899SCharles.Forsyth break; 10937da2899SCharles.Forsyth 11037da2899SCharles.Forsyth alt { 11137da2899SCharles.Forsyth r = <-readerchan => 11237da2899SCharles.Forsyth ; 11337da2899SCharles.Forsyth <-timerchan => 11437da2899SCharles.Forsyth tries++; 11537da2899SCharles.Forsyth continue; 11637da2899SCharles.Forsyth }; 11737da2899SCharles.Forsyth 11837da2899SCharles.Forsyth if(str->prefix(question + "=", r)){ 11937da2899SCharles.Forsyth reply = r[len question + 1:]; 12037da2899SCharles.Forsyth break; 12137da2899SCharles.Forsyth } 12237da2899SCharles.Forsyth } 12337da2899SCharles.Forsyth 12437da2899SCharles.Forsyth done = 1; 12537da2899SCharles.Forsyth killpid(readerpid); 12637da2899SCharles.Forsyth killpid(timerpid); 12737da2899SCharles.Forsyth return reply; 12837da2899SCharles.Forsyth} 12937da2899SCharles.Forsyth 13037da2899SCharles.Forsythcantload(s: string) 13137da2899SCharles.Forsyth{ 13237da2899SCharles.Forsyth sys->fprint(stderr, "virgil: can't load %s: %r\n", s); 13337da2899SCharles.Forsyth} 13437da2899SCharles.Forsyth 13537da2899SCharles.Forsythgetid(): string 13637da2899SCharles.Forsyth{ 13737da2899SCharles.Forsyth fd := sys->open("/dev/sysname", sys->OREAD); 13837da2899SCharles.Forsyth if(fd == nil) 13937da2899SCharles.Forsyth return "unknown"; 14037da2899SCharles.Forsyth buf := array[256] of byte; 14137da2899SCharles.Forsyth n := sys->read(fd, buf, len buf); 14237da2899SCharles.Forsyth if(n < 1) 14337da2899SCharles.Forsyth return "unknown"; 14437da2899SCharles.Forsyth return string buf[0:n]; 14537da2899SCharles.Forsyth} 14637da2899SCharles.Forsyth 14737da2899SCharles.Forsythreader(fd: ref sys->FD, cstring: chan of string, cpid: chan of int) 14837da2899SCharles.Forsyth{ 14937da2899SCharles.Forsyth pid := sys->pctl(0, nil); 15037da2899SCharles.Forsyth cpid <-= pid; 15137da2899SCharles.Forsyth 15237da2899SCharles.Forsyth buf := array[2048] of byte; 15337da2899SCharles.Forsyth n := sys->read(fd, buf, len buf); 15437da2899SCharles.Forsyth if(n <= Udphdrsize) 15537da2899SCharles.Forsyth return; 15637da2899SCharles.Forsyth 15737da2899SCharles.Forsyth # dump cruft 15837da2899SCharles.Forsyth for(i := Udphdrsize; i < n; i++) 15937da2899SCharles.Forsyth if((int buf[i]) == 0) 16037da2899SCharles.Forsyth break; 16137da2899SCharles.Forsyth 16237da2899SCharles.Forsyth if(!done) 16337da2899SCharles.Forsyth cstring <-= string buf[Udphdrsize:i]; 16437da2899SCharles.Forsyth} 16537da2899SCharles.Forsyth 16637da2899SCharles.Forsythtimer(c: chan of int) 16737da2899SCharles.Forsyth{ 16837da2899SCharles.Forsyth pid := sys->pctl(0, nil); 16937da2899SCharles.Forsyth c <-= pid; 17037da2899SCharles.Forsyth while(!done){ 17137da2899SCharles.Forsyth sys->sleep(1000); 17237da2899SCharles.Forsyth if(done) 17337da2899SCharles.Forsyth break; 17437da2899SCharles.Forsyth c <-= 1; 17537da2899SCharles.Forsyth } 17637da2899SCharles.Forsyth} 17737da2899SCharles.Forsyth 17837da2899SCharles.Forsythkillpid(pid: int) 17937da2899SCharles.Forsyth{ 18037da2899SCharles.Forsyth fd := sys->open("#p/"+(string pid)+"/ctl", sys->OWRITE); 18137da2899SCharles.Forsyth if(fd != nil) 18237da2899SCharles.Forsyth sys->fprint(fd, "kill"); 18337da2899SCharles.Forsyth} 184