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