xref: /inferno-os/appl/lib/venti.b (revision 2b69dba5038ffd0b59cf30a4c44bce549e5097f8)
1implement Venti;
2
3include "sys.m";
4	sys: Sys;
5	sprint: import sys;
6include "venti.m";
7
8BIT8SZ:	con 1;
9BIT16SZ:	con 2;
10BIT32SZ:	con 4;
11BIT48SZ:	con 6;
12SCORE:	con 20;
13STR:		con BIT16SZ;
14H: con BIT16SZ+BIT8SZ+BIT8SZ;		# minimum header length: size[2] op[1] tid[1]
15Rootnamelen: con 128;
16
17versions := array[] of {"02"};
18
19blankroot: Root;
20blankentry: Entry;
21
22init()
23{
24	sys = load Sys Sys->PATH;
25}
26
27hdrlen := array[Tmax] of {
28Rerror =>	H+STR,							# size[2] Rerror tid[1] error[s]
29Tping =>	H,								# size[2] Tping tid[1]
30Rping => 	H,								# size[2] Rping tid[1]
31Thello =>	H+STR+STR+BIT8SZ+BIT8SZ+BIT8SZ,	# size[2] Thello tid[1] version[s] uid[s] crypto[1] cryptos[n] codecs[n]
32Rhello =>	H+STR+BIT8SZ+BIT8SZ,				# size[2] Rhello tid[1] sid[s] crypto[1] codec[1]
33Tgoodbye => H,							# size[2] Tgoodbye tid[1]
34Tread =>	H+SCORE+BIT8SZ+BIT8SZ+BIT16SZ,	# size[2] Tread tid[1] score[20] type[1] pad[1] n[2]
35Rread => H,								# size[2] Rread tid[1] data
36Twrite => H+BIT8SZ+3,						# size[2] Twrite tid[1] type[1] pad[3]
37Rwrite => H+SCORE,							# size[2] Rwrite tid[1] score[20
38Tsync => H,								# size[2] Tsync tid[1]
39Rsync => H,								# size[2] Rsync tid[1]
40};
41
42tag2type := array[] of {
43tagof Vmsg.Rerror => Rerror,
44tagof Vmsg.Tping => Tping,
45tagof Vmsg.Rping => Rping,
46tagof Vmsg.Thello => Thello,
47tagof Vmsg.Rhello => Rhello,
48tagof Vmsg.Tgoodbye => Tgoodbye,
49tagof Vmsg.Tread => Tread,
50tagof Vmsg.Rread => Rread,
51tagof Vmsg.Twrite => Twrite,
52tagof Vmsg.Rwrite => Rwrite,
53tagof Vmsg.Tsync => Tsync,
54tagof Vmsg.Rsync => Rsync,
55};
56
57msgname := array[] of {
58tagof Vmsg.Rerror => "Rerror",
59tagof Vmsg.Tping => "Tping",
60tagof Vmsg.Rping => "Rping",
61tagof Vmsg.Thello => "Thello",
62tagof Vmsg.Rhello => "Rhello",
63tagof Vmsg.Tgoodbye => "Tgoodbye",
64tagof Vmsg.Tread => "Tread",
65tagof Vmsg.Rread => "Rread",
66tagof Vmsg.Twrite => "Twrite",
67tagof Vmsg.Rwrite => "Rwrite",
68tagof Vmsg.Tsync => "Tsync",
69tagof Vmsg.Rsync => "Rsync",
70};
71
72zero := array[] of {
73	byte 16rda, byte 16r39, byte 16ra3, byte 16ree, byte 16r5e,
74	byte 16r6b, byte 16r4b, byte 16r0d, byte 16r32, byte 16r55,
75	byte 16rbf, byte 16ref, byte 16r95, byte 16r60, byte 16r18,
76	byte 16r90, byte 16raf, byte 16rd8, byte 16r07, byte 16r09
77};
78
79
80Vmsg.read(fd: ref Sys->FD): (ref Vmsg, string)
81{
82	(msg, err) := readmsg(fd);
83	if(err != nil)
84		return (nil, err);
85	if(msg == nil)
86		return (nil, "eof reading message");
87	(nil, m) := Vmsg.unpack(msg);
88	if(m == nil)
89		return (nil, sys->sprint("bad venti message format: %r"));
90	return (m, nil);
91}
92
93Vmsg.unpack(f: array of byte): (int, ref Vmsg)
94{
95	if(len f < H) {
96		sys->werrstr("message too small");
97		return (0, nil);
98	}
99	size := (int f[0] << 8) | int f[1];		# size does not include self
100	size += BIT16SZ;
101	if(len f != size){
102		if(len f < size){
103			sys->werrstr("need more data");
104			return (0, nil);		# need more data
105		}
106		f = f[0:size];			# trim to exact length
107	}
108	mtype := int f[2];
109	if(mtype >= len hdrlen || size < hdrlen[mtype]){
110		sys->werrstr("mtype out of range");
111		return (-1, nil);
112	}
113	tid := int f[3];
114	m: ref Vmsg;
115	case mtype {
116	Thello =>
117		uid: string;
118		cryptos, codecs: array of byte;
119
120		(version, o) := gstring(f, H);
121		(uid, o) = gstring(f, o);
122		if(o < 0 || o >= len f)
123			break;
124		cryptostrength := int f[o++];
125		(cryptos, o) = gbytes(f, o);
126		(codecs, o) = gbytes(f, o);
127		if(o != len f)
128			break;
129		m = ref Vmsg.Thello(1, tid, version, uid, cryptostrength, cryptos, codecs);
130	Tping =>
131		m = ref Vmsg.Tping(1, tid);
132	Tgoodbye =>
133		m = ref Vmsg.Tgoodbye(1, tid);
134	Tread =>
135		score := Score(f[H:H+SCORE]);
136		etype := int f[H+SCORE];
137		n := (int f[H+SCORE+2] << 8) | int f[H+SCORE+3];
138		m = ref Vmsg.Tread(1, tid, score, etype, n);
139	Twrite =>
140		etype := int f[H];
141		m = ref Vmsg.Twrite(1, tid, etype, f[H+4:]);
142	Tsync =>
143		m = ref Vmsg.Tsync(1, tid);
144	Rhello =>
145		(sid, o) := gstring(f, H);
146		if(o+2 != len f)
147			break;
148		crypto := int f[o++];
149		codec := int f[o++];
150		m = ref Vmsg.Rhello(0, tid, sid, crypto, codec);
151	Rping =>
152		m = ref Vmsg.Rping(0, tid);
153	Rread =>
154		m = ref Vmsg.Rread(0, tid, f[H:]);
155	Rwrite =>
156		m = ref Vmsg.Rwrite(0, tid, Score(f[H:H+SCORE]));
157	Rsync =>
158		m = ref Vmsg.Rsync(0, tid);
159	Rerror =>
160		(err, o) := gstring(f, H);
161		if(o < 0)
162			break;
163		m = ref Vmsg.Rerror(0, tid, err);
164	* =>
165		sys->werrstr("unrecognised mtype " + string mtype);
166		return (-1, nil);
167	}
168	if(m == nil) {
169		sys->werrstr("bad message size");
170		return (-1, nil);
171	}
172	return (size, m);
173}
174
175Vmsg.pack(gm: self ref Vmsg): array of byte
176{
177	if(gm == nil)
178		return nil;
179	ds := gm.packedsize();
180	if(ds <= 0)
181		return nil;
182	d := array[ds] of byte;
183	d[0] = byte ((ds - 2) >> 8);
184	d[1] = byte (ds - 2);
185	d[2] = byte tag2type[tagof gm];
186	d[3] = byte gm.tid;
187	pick m := gm {
188	Thello =>
189		o := pstring(d, H, m.version);
190		o = pstring(d, o, m.uid);
191		d[o++] = byte m.cryptostrength;
192		d[o++] = byte len m.cryptos;
193		d[o:] = m.cryptos;
194		o += len m.cryptos;
195		d[o++] = byte len m.codecs;
196		d[o:] = m.codecs;
197		o += len m.codecs;
198	Tping =>
199		;
200	Tgoodbye =>
201		;
202	Tread =>
203		d[H:] = m.score.a;
204		d[H+SCORE] = byte m.etype;
205		d[H+SCORE+2] = byte (m.n >> 8);
206		d[H+SCORE+3] = byte m.n;
207	Twrite =>
208		d[H] = byte m.etype;
209		d[H+4:] = m.data;
210	Tsync =>
211		;
212	Rhello =>
213		o := pstring(d, H, m.sid);
214		d[o++] = byte m.crypto;
215		d[o++] = byte m.codec;
216	Rping =>
217		;
218	Rread =>
219		d[H:] = m.data;
220	Rwrite =>
221		d[H:] = m.score.a;
222	Rsync =>
223		;
224	Rerror =>
225		pstring(d, H, m.e);
226	* =>
227		return nil;
228	}
229	return d;
230}
231
232Vmsg.packedsize(gm: self ref Vmsg): int
233{
234	mtype := tag2type[tagof gm];
235	if(mtype <= 0)
236		return 0;
237	ml := hdrlen[mtype];
238	pick m := gm {
239	Thello =>
240		ml += utflen(m.version) + utflen(m.uid) + len m.cryptos + len m.codecs;
241	Rhello =>
242		ml += utflen(m.sid);
243	Rread =>
244		ml += len m.data;
245	Twrite =>
246		ml += len m.data;
247	Rerror =>
248		ml += utflen(m.e);
249	}
250	return ml;
251}
252
253Vmsg.text(gm: self ref Vmsg): string
254{
255	if(gm == nil)
256		return "(nil)";
257	s := sys->sprint("%s(%d", msgname[tagof gm], gm.tid);
258	pick m := gm {
259	* =>
260		s += ",ILLEGAL";
261	Thello =>
262		s += sys->sprint(", %#q, %#q, %d, [", m.version, m.uid, m.cryptostrength);
263		if(len m.cryptos > 0){
264			s += string int m.cryptos[0];
265			for(i := 1; i < len m.cryptos; i++)
266				s += "," + string int m.cryptos[i];
267		}
268		s += "], [";
269		if(len m.codecs > 0){
270			s += string int m.codecs[0];
271			for(i := 1; i < len m.codecs; i++)
272				s += "," + string int m.codecs[i];
273		}
274		s += "]";
275	Tping =>
276		;
277	Tgoodbye =>
278		;
279	Tread =>
280		s += sys->sprint(", %s, %d, %d", m.score.text(), m.etype, m.n);
281	Twrite =>
282		s += sys->sprint(", %d, data[%d]", m.etype, len m.data);
283	Tsync =>
284		;
285	Rhello =>
286		s += sys->sprint(", %#q, %d, %d", m.sid, m.crypto, m.codec);
287	Rping =>
288	Rread =>
289		s += sys->sprint(", data[%d]", len m.data);
290	Rwrite =>
291		s += ", " + m.score.text();
292	Rsync =>
293		;
294	Rerror =>
295		s += sys->sprint(", %#q", m.e);
296	}
297	return s + ")";
298}
299
300Session.new(fd: ref Sys->FD): ref Session
301{
302	s := "venti-";
303	for(i := 0; i < len versions; i++){
304		if(i != 0)
305			s[len s] = ':';
306		s += versions[i];
307	}
308	s += "-libventi\n";
309	d := array of byte s;
310	if(sys->write(fd, d, len d) != len d)
311		return nil;
312	version := readversion(fd, "venti-", versions);
313	if(version == nil)
314		return nil;
315	session := ref Session(fd, version);
316	(r, e) := session.rpc(ref Vmsg.Thello(1, 0, version, nil, 0, nil, nil));
317	if(r == nil){
318		sys->werrstr("hello failed: " + e);
319		return nil;
320	}
321	return ref Session(fd, version);
322}
323
324Session.read(s: self ref Session, score: Score, etype: int, maxn: int): array of byte
325{
326	(gm, err) := s.rpc(ref Vmsg.Tread(1, 0, score, etype, maxn));
327	if(gm == nil){
328		sys->werrstr(err);
329		return nil;
330	}
331	pick m := gm {
332	Rread =>
333		return m.data;
334	}
335	return nil;
336}
337
338Session.write(s: self ref Session, etype: int, data: array of byte): (int, Score)
339{
340	(gm, err) := s.rpc(ref Vmsg.Twrite(1, 0, etype, data));
341	if(gm == nil){
342		sys->werrstr(err);
343		return (-1, Score(nil));
344	}
345	pick m := gm {
346	Rwrite =>
347		return (0, m.score);
348	}
349	return (-1, Score(nil));
350}
351
352Session.sync(s: self ref Session): int
353{
354	(gm, err) := s.rpc(ref Vmsg.Tsync(1, 0));
355	if(gm == nil){
356		sys->werrstr(err);
357		return -1;
358	}
359	return 0;
360}
361
362Session.rpc(s: self ref Session, m: ref Vmsg): (ref Vmsg, string)
363{
364	d := m.pack();
365	if(sys->write(s.fd, d, len d) != len d)
366		return (nil, "write failed");
367	(grm, err) := Vmsg.read(s.fd);
368	if(grm == nil)
369		return (nil, err);
370	if(grm.tid != m.tid)
371		return (nil, "message tags don't match");
372	if(grm.istmsg)
373		return (nil, "reply message is a t-message");
374	pick rm := grm {
375	Rerror =>
376		return (nil, rm.e);
377	}
378	if(tagof(grm) != tagof(m) + 1)
379		return (nil, "reply message is of wrong type");
380	return (grm, nil);
381}
382
383readversion(fd: ref Sys->FD, prefix: string, versions: array of string): string
384{
385	buf := array[Maxstringsize] of byte;
386	i := 0;
387	for(;;){
388		if(i >= len buf){
389			sys->werrstr("initial version string too long");
390			return nil;
391		}
392		if(readn(fd, buf[i:], 1) != 1){
393			sys->werrstr("eof on version string");
394			return nil;
395		}
396		c := int buf[i];
397		if(c == '\n')
398			break;
399		if(c < ' ' || c > 16r7f || i < len prefix && prefix[i] != c){
400			sys->werrstr("bad version string");
401			return nil;
402		}
403		i++;
404	}
405	if(i < len prefix){
406		sys->werrstr("bad version string");
407		return nil;
408	}
409#sys->fprint(sys->fildes(2), "read version %#q\n", string buf[0:i]);
410	v := string buf[len prefix:i];
411	i = 0;
412	for(;;){
413		for(j := i; j < len v && v[j] != ':' && v[j] != '-'; j++)
414			;
415		vv := v[i:j];
416#sys->fprint(sys->fildes(2), "checking %#q\n", vv);
417		for(k := 0; k < len versions; k++)
418			if(versions[k] == vv)
419				return vv;
420		i = j;
421		if(i >= len v || v[i] != ':'){
422			sys->werrstr("unknown version");
423			return nil;
424		}
425		i++;
426	}
427	sys->werrstr("unknown version");
428	return nil;
429}
430
431
432Score.eq(a: self Score, b: Score): int
433{
434	for(i := 0; i < SCORE; i++)
435		if(a.a[i] != b.a[i])
436			return 0;
437	return 1;
438}
439
440Score.zero(): Score
441{
442	return Score(zero);
443}
444
445Score.parse(s: string): (int, Score)
446{
447	if(len s != Scoresize * 2)
448		return (-1, Score(nil));
449	score := array[Scoresize] of {* => byte 0};
450	for(i := 0; i < len s; i++){
451		c := s[i];
452		case s[i] {
453		'0' to '9' =>
454			c -= '0';
455		'a' to 'f' =>
456			c -= 'a' - 10;
457		'A' to 'F' =>
458			c -= 'A' - 10;
459		* =>
460			return (-1, Score(nil));
461		}
462		if((i & 1) == 0)
463			c <<= 4;
464		score[i>>1] |= byte c;
465	}
466	return (0, Score(score));
467}
468
469Score.text(a: self Score): string
470{
471	s := "";
472	for(i := 0; i < SCORE; i++)
473		s += sys->sprint("%.2ux", int a.a[i]);
474	return s;
475}
476
477readn(fd: ref Sys->FD, buf: array of byte, nb: int): int
478{
479	for(nr := 0; nr < nb;){
480		n := sys->read(fd, buf[nr:], nb-nr);
481		if(n <= 0){
482			if(nr == 0)
483				return n;
484			break;
485		}
486		nr += n;
487	}
488	return nr;
489}
490
491readmsg(fd: ref Sys->FD): (array of byte, string)
492{
493	sbuf := array[BIT16SZ] of byte;
494	if((n := readn(fd, sbuf, BIT16SZ)) != BIT16SZ){
495		if(n == 0)
496			return (nil, nil);
497		return (nil, sys->sprint("%r"));
498	}
499	ml := (int sbuf[0] << 8) | int sbuf[1];
500	if(ml < BIT16SZ)
501		return (nil, "invalid venti message size");
502	buf := array[ml + BIT16SZ] of byte;
503	buf[0:] = sbuf;
504	if((n = readn(fd, buf[BIT16SZ:], ml)) != ml){
505		if(n == 0)
506			return (nil, "venti message truncated");
507		return (nil, sys->sprint("%r"));
508	}
509	return (buf, nil);
510}
511
512pstring(a: array of byte, o: int, s: string): int
513{
514	sa := array of byte s;	# could do conversion ourselves
515	n := len sa;
516	a[o] = byte (n >> 8);
517	a[o+1] = byte n;
518	a[o+2:] = sa;
519	return o+STR+n;
520}
521
522gstring(a: array of byte, o: int): (string, int)
523{
524	if(o < 0 || o+STR > len a)
525		return (nil, -1);
526	l := (int a[o] << 8) | int a[o+1];
527	if(l > Maxstringsize)
528		return (nil, -1);
529	o += STR;
530	e := o+l;
531	if(e > len a)
532		return (nil, -1);
533	return (string a[o:e], e);
534}
535
536gbytes(a: array of byte, o: int): (array of byte, int)
537{
538	if(o < 0 || o+1 > len a)
539		return (nil, -1);
540	n := int a[o];
541	if(1+n > len a)
542		return (nil, -1);
543	no := o+1+n;
544	return (a[o+1:no], no);
545}
546
547utflen(s: string): int
548{
549	# the domain is 16-bit unicode only, which is all that Inferno now implements
550	n := l := len s;
551	for(i:=0; i<l; i++)
552		if((c := s[i]) > 16r7F){
553			n++;
554			if(c > 16r7FF)
555				n++;
556		}
557	return n;
558}
559
560gtstring(a: array of byte, o: int, n: int): string
561{
562	e := o + n;
563	if(e > len a)
564		return nil;
565	for(i := o; i < e; i++)
566		if(a[i] == byte 0)
567			break;
568	return string a[o:i];
569}
570
571Root.pack(r: self ref Root): array of byte
572{
573	d := array[Rootsize] of byte;
574	i := 0;
575	i = p16(d, i, r.version);
576	i = ptstring(d, i, r.name, Rootnamelen);
577	if(i < 0)
578		return nil;
579	i = ptstring(d, i, r.rtype, Rootnamelen);
580	if(i < 0)
581		return nil;
582	i = pscore(d, i, r.score);
583	i = p16(d, i, r.blocksize);
584	if(r.prev == nil) {
585		for(j := 0; j < Scoresize; j++)
586			d[i+j] = byte 0;
587		i += Scoresize;
588	} else
589		i = pscore(d, i, *r.prev);
590	if(i != len d) {
591		sys->werrstr("root pack, bad length: "+string i);
592		return nil;
593	}
594	return d;
595}
596
597Root.unpack(d: array of byte): ref Root
598{
599	if(len d != Rootsize){
600		sys->werrstr("root entry is wrong length");
601		return nil;
602	}
603	r := ref blankroot;
604	r.version = g16(d, 0);
605	if(r.version != Rootversion){
606		sys->werrstr("unknown root version");
607		return nil;
608	}
609	o := BIT16SZ;
610	r.name = gtstring(d, o, Rootnamelen);
611	o += Rootnamelen;
612	r.rtype = gtstring(d, o, Rootnamelen);
613	o += Rootnamelen;
614	r.score = gscore(d, o);
615	o += Scoresize;
616	r.blocksize = g16(d, o);
617	o += BIT16SZ;
618	prev := gscore(d, o);
619	if(!prev.eq(Score(array[Scoresize] of {* => byte 0})))
620		r.prev = ref prev;
621	return r;
622}
623
624
625Entry.pack(e: self ref Entry): array of byte
626{
627	d := array[Entrysize] of byte;
628	i := 0;
629	i = p32(d, i, e.gen);
630	i = p16(d, i, e.psize);
631	i = p16(d, i, e.dsize);
632	e.flags |= e.depth<<Entrydepthshift;
633	d[i++] = byte e.flags;
634	for(j := 0; j < 5; j++)
635		d[i++] = byte 0;
636	i = p48(d, i, e.size);
637	i = pscore(d, i, e.score);
638	if(i != len d) {
639		sys->werrstr(sprint("bad length, have %d, want %d", i, len d));
640		return nil;
641	}
642	return d;
643}
644
645Entry.unpack(d: array of byte): ref Entry
646{
647	if(len d != Entrysize){
648		sys->werrstr("entry is wrong length");
649		return nil;
650	}
651	e := ref blankentry;
652	i := 0;
653	e.gen = g32(d, i);
654	i += BIT32SZ;
655	e.psize = g16(d, i);
656	i += BIT16SZ;
657	e.dsize = g16(d, i);
658	i += BIT16SZ;
659	e.flags = int d[i];
660	e.depth = (e.flags & Entrydepthmask) >> Entrydepthshift;
661	e.flags &= ~Entrydepthmask;
662	i += BIT8SZ;
663	i += 5;			# skip something...
664	e.size = g48(d, i);
665	i += BIT48SZ;
666	e.score = gscore(d, i);
667	i += Scoresize;
668	if((e.flags & Entryactive) == 0)
669		return e;
670	if(!checksize(e.psize) || !checksize(e.dsize)){
671		sys->werrstr(sys->sprint("bad blocksize (%d or %d)", e.psize, e.dsize));
672		return nil;
673	}
674	return e;
675}
676
677checksize(n: int): int
678{
679	if(n < 256 || n > Maxlumpsize) {
680		sys->werrstr("bad block size");
681		return 0;
682	}
683	return 1;
684}
685
686gscore(f: array of byte, i: int): Score
687{
688	s := Score(array[Scoresize] of byte);
689	s.a[0:] = f[i:i+Scoresize];
690	return s;
691}
692
693g16(f: array of byte, i: int): int
694{
695	return (int f[i] << 8) | int f[i+1];
696}
697
698g32(f: array of byte, i: int): int
699{
700	return (((((int f[i+0] << 8) | int f[i+1]) << 8) | int f[i+2]) << 8) | int f[i+3];
701}
702
703g48(f: array of byte, i: int): big
704{
705	b1 := (((((int f[i+0] << 8) | int f[i+1]) << 8) | int f[i+2]) << 8) | int f[i+3];
706	b0 := (int f[i+4] << 8) | int f[i+5];
707	return (big b1 << 16) | big b0;
708}
709
710g64(f: array of byte, i: int): big
711{
712	b0 := (((((int f[i+0] << 8) | int f[i+1]) << 8) | int f[i+2]) << 8) | int f[i+3];
713	b1 := (((((int f[i+4] << 8) | int f[i+5]) << 8) | int f[i+6]) << 8) | int f[i+7];
714	return (big b0 << 32) | (big b1 & 16rFFFFFFFF);
715}
716
717p16(d: array of byte, i: int, v: int): int
718{
719	d[i+0] = byte (v>>8);
720	d[i+1] = byte v;
721	return i+BIT16SZ;
722}
723
724p32(d: array of byte, i: int, v: int): int
725{
726	p16(d, i+0, v>>16);
727	p16(d, i+2, v);
728	return i+BIT32SZ;
729}
730
731p48(d: array of byte, i: int, v: big): int
732{
733	p16(d, i+0, int (v>>32));
734	p32(d, i+2, int v);
735	return i+BIT48SZ;
736}
737
738ptstring(d: array of byte, i: int, s: string, l: int): int
739{
740	a := array of byte s;
741	if(len a > l) {
742		sys->werrstr("string too long: "+s);
743		return -1;
744	}
745	for(j := 0; j < len a; j++)
746		d[i+j] = a[j];
747	while(j < l)
748		d[i+j++] = byte 0;
749	return i+l;
750}
751
752pscore(d: array of byte, i: int, s: Score): int
753{
754	for(j := 0; j < Scoresize; j++)
755		d[i+j] = s.a[j];
756	return i+Scoresize;
757}
758