xref: /inferno-os/appl/lib/virgil.b (revision fbc1184c08d18d5ac0f8763a058e015e95353341)
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