summaryrefslogtreecommitdiff
path: root/appl/lib/virgil.b
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /appl/lib/virgil.b
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'appl/lib/virgil.b')
-rw-r--r--appl/lib/virgil.b177
1 files changed, 177 insertions, 0 deletions
diff --git a/appl/lib/virgil.b b/appl/lib/virgil.b
new file mode 100644
index 00000000..eb68671b
--- /dev/null
+++ b/appl/lib/virgil.b
@@ -0,0 +1,177 @@
+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->OUdphdrlen; # use oldheaders format for compatibility
+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;
+ sys->fprint(c.cfd, "oldheaders");
+ 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");
+}