13e12c5d1SDavid du Colombier #include <u.h> 23e12c5d1SDavid du Colombier #include <libc.h> 33e12c5d1SDavid du Colombier 43e12c5d1SDavid du Colombier enum { 53e12c5d1SDavid du Colombier Soh= 0x1, 63e12c5d1SDavid du Colombier Eot= 0x4, 73e12c5d1SDavid du Colombier Ack= 0x6, 83e12c5d1SDavid du Colombier Nak= 0x15, 93e12c5d1SDavid du Colombier Cancel= 0x18, 103e12c5d1SDavid du Colombier }; 113e12c5d1SDavid du Colombier 123e12c5d1SDavid du Colombier int notifyf(void*, char*); 133e12c5d1SDavid du Colombier int readupto(uchar*, int); 143e12c5d1SDavid du Colombier int receive(int, uchar); 153e12c5d1SDavid du Colombier void send(int); 163e12c5d1SDavid du Colombier 173e12c5d1SDavid du Colombier int debug, dfd; 183e12c5d1SDavid du Colombier 193e12c5d1SDavid du Colombier void 203e12c5d1SDavid du Colombier main(int argc, char **argv) 213e12c5d1SDavid du Colombier { 223e12c5d1SDavid du Colombier int fd; 233e12c5d1SDavid du Colombier uchar seqno; 243e12c5d1SDavid du Colombier ulong bytes; 253e12c5d1SDavid du Colombier 263e12c5d1SDavid du Colombier ARGBEGIN { 273e12c5d1SDavid du Colombier case 'd': 283e12c5d1SDavid du Colombier dfd = 2; 293e12c5d1SDavid du Colombier debug = 1; 303e12c5d1SDavid du Colombier break; 313e12c5d1SDavid du Colombier } ARGEND 323e12c5d1SDavid du Colombier 333e12c5d1SDavid du Colombier if(argc != 1){ 343e12c5d1SDavid du Colombier fprint(2, "usage: xmr filename\n"); 353e12c5d1SDavid du Colombier exits("usage"); 363e12c5d1SDavid du Colombier } 373e12c5d1SDavid du Colombier fd = open("/dev/consctl", OWRITE); 38*80ee5cbfSDavid du Colombier if(fd >= 0) 393e12c5d1SDavid du Colombier write(fd, "rawon", 5); 403e12c5d1SDavid du Colombier fd = create(argv[0], ORDWR, 0666); 413e12c5d1SDavid du Colombier if(fd < 0){ 42219b2ee8SDavid du Colombier perror("xmr: create"); 43219b2ee8SDavid du Colombier exits("create"); 443e12c5d1SDavid du Colombier } 453e12c5d1SDavid du Colombier 463e12c5d1SDavid du Colombier atnotify(notifyf, 1); 473e12c5d1SDavid du Colombier send(Nak); 483e12c5d1SDavid du Colombier 493e12c5d1SDavid du Colombier /* 503e12c5d1SDavid du Colombier * keep receiving till the other side gives up 513e12c5d1SDavid du Colombier */ 523e12c5d1SDavid du Colombier bytes = 0; 533e12c5d1SDavid du Colombier for(seqno = 1; ; seqno++){ 543e12c5d1SDavid du Colombier if(receive(fd, seqno) == -1) 553e12c5d1SDavid du Colombier break; 563e12c5d1SDavid du Colombier bytes += 128; 573e12c5d1SDavid du Colombier } 587dd7cddfSDavid du Colombier fprint(2, "xmr: received %ld bytes\n", bytes); 593e12c5d1SDavid du Colombier exits(0); 603e12c5d1SDavid du Colombier } 613e12c5d1SDavid du Colombier 623e12c5d1SDavid du Colombier void 633e12c5d1SDavid du Colombier send(int byte) 643e12c5d1SDavid du Colombier { 653e12c5d1SDavid du Colombier uchar c; 663e12c5d1SDavid du Colombier 673e12c5d1SDavid du Colombier c = byte; 683e12c5d1SDavid du Colombier if(write(1, &c, 1) != 1){ 693e12c5d1SDavid du Colombier fprint(2, "xmr: hungup\n"); 703e12c5d1SDavid du Colombier exits("hangup"); 713e12c5d1SDavid du Colombier } 723e12c5d1SDavid du Colombier } 733e12c5d1SDavid du Colombier 743e12c5d1SDavid du Colombier int 753e12c5d1SDavid du Colombier readupto(uchar *a, int len) 763e12c5d1SDavid du Colombier { 773e12c5d1SDavid du Colombier int n; 783e12c5d1SDavid du Colombier int sofar; 793e12c5d1SDavid du Colombier 803e12c5d1SDavid du Colombier for(sofar = 0; sofar < len; sofar += n){ 813e12c5d1SDavid du Colombier n = read(0, a, len-sofar); 823e12c5d1SDavid du Colombier if(n <= 0){ 833e12c5d1SDavid du Colombier send(Nak); 843e12c5d1SDavid du Colombier return sofar; 853e12c5d1SDavid du Colombier } 863e12c5d1SDavid du Colombier if(*a == Eot || *a == Cancel) 873e12c5d1SDavid du Colombier return sofar + n; 883e12c5d1SDavid du Colombier a += n; 893e12c5d1SDavid du Colombier } 903e12c5d1SDavid du Colombier return sofar; 913e12c5d1SDavid du Colombier 923e12c5d1SDavid du Colombier } 933e12c5d1SDavid du Colombier 943e12c5d1SDavid du Colombier int 953e12c5d1SDavid du Colombier receive(int fd, uchar seqno) 963e12c5d1SDavid du Colombier { 973e12c5d1SDavid du Colombier uchar buf[128+4]; 983e12c5d1SDavid du Colombier uchar sum; 993e12c5d1SDavid du Colombier uchar *p; 1003e12c5d1SDavid du Colombier int n; 1013e12c5d1SDavid du Colombier int tries; 1023e12c5d1SDavid du Colombier int have; 1033e12c5d1SDavid du Colombier 1043e12c5d1SDavid du Colombier for(have = 0, tries = 0;; tries++){ 1053e12c5d1SDavid du Colombier if(debug) 1063e12c5d1SDavid du Colombier fprint(dfd, "have == %d\n", have); 1073e12c5d1SDavid du Colombier if(tries > 10){ 1083e12c5d1SDavid du Colombier fprint(2, "xmr: timed out\n"); 1093e12c5d1SDavid du Colombier if(debug) 1103e12c5d1SDavid du Colombier close(dfd); 1113e12c5d1SDavid du Colombier exits("timeout"); 1123e12c5d1SDavid du Colombier } 1133e12c5d1SDavid du Colombier 1143e12c5d1SDavid du Colombier /* try to gather up a block */ 1153e12c5d1SDavid du Colombier alarm(15*1000); 1163e12c5d1SDavid du Colombier n = readupto(&buf[have], 132-have); 1173e12c5d1SDavid du Colombier alarm(0); 1183e12c5d1SDavid du Colombier have += n; 1193e12c5d1SDavid du Colombier if(have){ 1203e12c5d1SDavid du Colombier switch(buf[0]){ 1213e12c5d1SDavid du Colombier case Eot: 1223e12c5d1SDavid du Colombier send(Ack); 1233e12c5d1SDavid du Colombier return -1; 1243e12c5d1SDavid du Colombier case Cancel: 1253e12c5d1SDavid du Colombier fprint(2, "xmr: transfer aborted by sender\n"); 1263e12c5d1SDavid du Colombier exits("cancel"); 1273e12c5d1SDavid du Colombier } 1283e12c5d1SDavid du Colombier } 1293e12c5d1SDavid du Colombier if(have != 132) 1303e12c5d1SDavid du Colombier continue; 1313e12c5d1SDavid du Colombier 1323e12c5d1SDavid du Colombier /* checksum */ 1333e12c5d1SDavid du Colombier for(p = buf, sum = 0; p < &buf[128+3]; p++) 1343e12c5d1SDavid du Colombier sum += *p; 1353e12c5d1SDavid du Colombier 1363e12c5d1SDavid du Colombier /* If invalid block, resynchronize */ 1373e12c5d1SDavid du Colombier if(buf[0] != Soh || buf[2] != (255-buf[1]) || sum != buf[131]){ 1383e12c5d1SDavid du Colombier if(debug){ 139*80ee5cbfSDavid du Colombier fprint(dfd, "resync %2.2ux %d %d %ux %ux\n", buf[0], 1403e12c5d1SDavid du Colombier buf[1], buf[2], sum, buf[131]); 14159cc4ca5SDavid du Colombier write(dfd, (char*)buf+3, 128); 14259cc4ca5SDavid du Colombier fprint(dfd, "\n"); 1433e12c5d1SDavid du Colombier } 1443e12c5d1SDavid du Colombier p = memchr(buf+1, Soh, 131); 1453e12c5d1SDavid du Colombier if(p){ 1463e12c5d1SDavid du Colombier have = 132-(p-buf); 1473e12c5d1SDavid du Colombier memmove(buf, p, have); 1483e12c5d1SDavid du Colombier } else 1493e12c5d1SDavid du Colombier have = 0; 1503e12c5d1SDavid du Colombier continue; 1513e12c5d1SDavid du Colombier } 1523e12c5d1SDavid du Colombier 1533e12c5d1SDavid du Colombier /* it's probably a real block, so dump it if there's an error */ 1543e12c5d1SDavid du Colombier have = 0; 1553e12c5d1SDavid du Colombier 1563e12c5d1SDavid du Colombier /* if this is the last block, ack */ 1573e12c5d1SDavid du Colombier if(buf[1] == seqno-1){ 1583e12c5d1SDavid du Colombier tries = 0; 1593e12c5d1SDavid du Colombier send(Ack); 1603e12c5d1SDavid du Colombier }else if(buf[1] == seqno){ 1613e12c5d1SDavid du Colombier if(debug) 1623e12c5d1SDavid du Colombier fprint(dfd, "Ack\n"); 1633e12c5d1SDavid du Colombier send(Ack); 1643e12c5d1SDavid du Colombier if(write(fd, buf+3, 128) != 128){ 1653e12c5d1SDavid du Colombier fprint(2, "xmr: abort, error writing file\n"); 1663e12c5d1SDavid du Colombier exits("write"); 1673e12c5d1SDavid du Colombier } 1683e12c5d1SDavid du Colombier return 0; 1693e12c5d1SDavid du Colombier } else { 1703e12c5d1SDavid du Colombier send(Nak); 1713e12c5d1SDavid du Colombier } 1723e12c5d1SDavid du Colombier } 1733e12c5d1SDavid du Colombier return -1; 1743e12c5d1SDavid du Colombier } 1753e12c5d1SDavid du Colombier 1763e12c5d1SDavid du Colombier int 1773e12c5d1SDavid du Colombier notifyf(void *a, char *msg) 1783e12c5d1SDavid du Colombier { 1793e12c5d1SDavid du Colombier USED(a); 1803e12c5d1SDavid du Colombier if(strcmp(msg, "alarm") == 0) 1813e12c5d1SDavid du Colombier return 1; 1823e12c5d1SDavid du Colombier return 0; 1833e12c5d1SDavid du Colombier } 184