implement Virgil; include "sys.m"; sys: Sys;include "string.m";include "keyring.m";include "draw.m";include "security.m";include "ip.m"; ip: IP; IPaddr, Udphdr: import ip; stderr: ref Sys->FD;done: int;Udphdrsize: con IP->Udphdrlen;Virgilport: con 2202; ## this module is very udp dependent. it shouldn't be. -- presotto# Call with first element of argv an arbitrary string, which is# discarded here. argv must also contain at least a question.#virgil(argv: list of string): string{ s,question,reply,r : string; timerpid, readerpid: int; if (argv == nil || tl argv == nil || hd (tl argv) == nil) return nil; done = 0; sys = load Sys Sys->PATH; str := load String String->PATH; if(str == nil){ cantload(String->PATH); return nil; } ip = load IP IP->PATH; if(ip == nil){ cantload(IP->PATH); return nil; } ip->init(); stderr = sys->fildes(2); # We preserve the convention that the first arg is not an option. # Undocumented '-v address' option allows passing in address # of virgild, circumventing broadcast. Used for development, # to avoid pestering servers on network. dest := ip->v4bcast; argv = tl argv; s = hd argv; if(s[0] == '-') { if(s[1] != 'v') return nil; argv = tl argv; if (argv == nil) return nil; s = hd argv; ok: int; (ok, dest) = IPaddr.parse(s); if(ok < 0){ sys->fprint(stderr, "virgil: invalid IP address %s\n", s); return nil; } argv = tl argv; } # Is there a question? if (argv == nil) return nil; question = hd argv; (ok, c) := sys->announce("udp!*!0"); if(ok < 0) return nil; if(sys->fprint(c.cfd, "headers") < 0) return nil; c.dfd = sys->open(c.dir+"/data", sys->ORDWR); if(c.dfd == nil) return nil; readerchan := chan of string; timerchan := chan of int; readerpidchan := chan of int; spawn timer(timerchan); timerpid = <-timerchan; spawn reader(c.dfd, readerchan, readerpidchan); readerpid = <-readerpidchan; question = getid() + "?" + question; qbuf := array of byte question; hdr := Udphdr.new(); hdr.raddr = dest; hdr.rport = Virgilport; buf := array[Udphdrsize + len qbuf] of byte; buf[Udphdrsize:] = qbuf; hdr.pack(buf, Udphdrsize); for(tries := 0; tries < 5; ){ if(sys->write(c.dfd, buf, len buf) < 0) break; alt { r = <-readerchan => ; <-timerchan => tries++; continue; }; if(str->prefix(question + "=", r)){ reply = r[len question + 1:]; break; } } done = 1; killpid(readerpid); killpid(timerpid); return reply;} cantload(s: string){ sys->fprint(stderr, "virgil: can't load %s: %r\n", s);} getid(): string{ fd := sys->open("/dev/sysname", sys->OREAD); if(fd == nil) return "unknown"; buf := array[256] of byte; n := sys->read(fd, buf, len buf); if(n < 1) return "unknown"; return string buf[0:n];} reader(fd: ref sys->FD, cstring: chan of string, cpid: chan of int){ pid := sys->pctl(0, nil); cpid <-= pid; buf := array[2048] of byte; n := sys->read(fd, buf, len buf); if(n <= Udphdrsize) return; # dump cruft for(i := Udphdrsize; i < n; i++) if((int buf[i]) == 0) break; if(!done) cstring <-= string buf[Udphdrsize:i];} timer(c: chan of int){ pid := sys->pctl(0, nil); c <-= pid; while(!done){ sys->sleep(1000); if(done) break; c <-= 1; }} killpid(pid: int){ fd := sys->open("#p/"+(string pid)+"/ctl", sys->OWRITE); if(fd != nil) sys->fprint(fd, "kill");}
implement Virgil;
include "sys.m";
sys: Sys;
include "string.m";
include "keyring.m";
include "draw.m";
include "security.m";
include "ip.m";
ip: IP;
IPaddr, Udphdr: import ip;
stderr: ref Sys->FD;
done: int;
Udphdrsize: con IP->Udphdrlen;
Virgilport: con 2202;
#
# this module is very udp dependent. it shouldn't be. -- presotto
# Call with first element of argv an arbitrary string, which is
# discarded here. argv must also contain at least a question.
#
virgil(argv: list of string): string
{
s,question,reply,r : string;
timerpid, readerpid: int;
if (argv == nil || tl argv == nil || hd (tl argv) == nil)
return nil;
done = 0;
sys = load Sys Sys->PATH;
str := load String String->PATH;
if(str == nil){
cantload(String->PATH);
return nil;
}
ip = load IP IP->PATH;
if(ip == nil){
cantload(IP->PATH);
return nil;
}
ip->init();
stderr = sys->fildes(2);
# We preserve the convention that the first arg is not an option.
# Undocumented '-v address' option allows passing in address
# of virgild, circumventing broadcast. Used for development,
# to avoid pestering servers on network.
dest := ip->v4bcast;
argv = tl argv;
s = hd argv;
if(s[0] == '-') {
if(s[1] != 'v')
return nil;
argv = tl argv;
if (argv == nil)
return nil;
s = hd argv;
ok: int;
(ok, dest) = IPaddr.parse(s);
if(ok < 0){
sys->fprint(stderr, "virgil: invalid IP address %s\n", s);
return nil;
}
argv = tl argv;
}
# Is there a question?
if (argv == nil)
return nil;
question = hd argv;
(ok, c) := sys->announce("udp!*!0");
if(ok < 0)
return nil;
if(sys->fprint(c.cfd, "headers") < 0)
return nil;
c.dfd = sys->open(c.dir+"/data", sys->ORDWR);
if(c.dfd == nil)
return nil;
readerchan := chan of string;
timerchan := chan of int;
readerpidchan := chan of int;
spawn timer(timerchan);
timerpid = <-timerchan;
spawn reader(c.dfd, readerchan, readerpidchan);
readerpid = <-readerpidchan;
question = getid() + "?" + question;
qbuf := array of byte question;
hdr := Udphdr.new();
hdr.raddr = dest;
hdr.rport = Virgilport;
buf := array[Udphdrsize + len qbuf] of byte;
buf[Udphdrsize:] = qbuf;
hdr.pack(buf, Udphdrsize);
for(tries := 0; tries < 5; ){
if(sys->write(c.dfd, buf, len buf) < 0)
break;
alt {
r = <-readerchan =>
;
<-timerchan =>
tries++;
continue;
};
if(str->prefix(question + "=", r)){
reply = r[len question + 1:];
break;
}
}
done = 1;
killpid(readerpid);
killpid(timerpid);
return reply;
}
cantload(s: string)
{
sys->fprint(stderr, "virgil: can't load %s: %r\n", s);
}
getid(): string
{
fd := sys->open("/dev/sysname", sys->OREAD);
if(fd == nil)
return "unknown";
buf := array[256] of byte;
n := sys->read(fd, buf, len buf);
if(n < 1)
return "unknown";
return string buf[0:n];
}
reader(fd: ref sys->FD, cstring: chan of string, cpid: chan of int)
{
pid := sys->pctl(0, nil);
cpid <-= pid;
buf := array[2048] of byte;
n := sys->read(fd, buf, len buf);
if(n <= Udphdrsize)
return;
# dump cruft
for(i := Udphdrsize; i < n; i++)
if((int buf[i]) == 0)
break;
if(!done)
cstring <-= string buf[Udphdrsize:i];
}
timer(c: chan of int)
{
pid := sys->pctl(0, nil);
c <-= pid;
while(!done){
sys->sleep(1000);
if(done)
break;
c <-= 1;
}
}
killpid(pid: int)
{
fd := sys->open("#p/"+(string pid)+"/ctl", sys->OWRITE);
if(fd != nil)
sys->fprint(fd, "kill");
}