176 lines · 3.3 KB · Brainfuck
RawDownload
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");}