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); 383e12c5d1SDavid du Colombier if(fd < 0){ 39219b2ee8SDavid du Colombier perror("xmr: open consctl"); 403e12c5d1SDavid du Colombier exits("consctl"); 413e12c5d1SDavid du Colombier } 423e12c5d1SDavid du Colombier write(fd, "rawon", 5); 433e12c5d1SDavid du Colombier fd = create(argv[0], ORDWR, 0666); 443e12c5d1SDavid du Colombier if(fd < 0){ 45219b2ee8SDavid du Colombier perror("xmr: create"); 46219b2ee8SDavid du Colombier exits("create"); 473e12c5d1SDavid du Colombier } 483e12c5d1SDavid du Colombier 493e12c5d1SDavid du Colombier atnotify(notifyf, 1); 503e12c5d1SDavid du Colombier send(Nak); 513e12c5d1SDavid du Colombier 523e12c5d1SDavid du Colombier /* 533e12c5d1SDavid du Colombier * keep receiving till the other side gives up 543e12c5d1SDavid du Colombier */ 553e12c5d1SDavid du Colombier bytes = 0; 563e12c5d1SDavid du Colombier for(seqno = 1; ; seqno++){ 573e12c5d1SDavid du Colombier if(receive(fd, seqno) == -1) 583e12c5d1SDavid du Colombier break; 593e12c5d1SDavid du Colombier bytes += 128; 603e12c5d1SDavid du Colombier } 61*7dd7cddfSDavid du Colombier fprint(2, "xmr: received %ld bytes\n", bytes); 623e12c5d1SDavid du Colombier exits(0); 633e12c5d1SDavid du Colombier } 643e12c5d1SDavid du Colombier 653e12c5d1SDavid du Colombier void 663e12c5d1SDavid du Colombier send(int byte) 673e12c5d1SDavid du Colombier { 683e12c5d1SDavid du Colombier uchar c; 693e12c5d1SDavid du Colombier 703e12c5d1SDavid du Colombier c = byte; 713e12c5d1SDavid du Colombier if(write(1, &c, 1) != 1){ 723e12c5d1SDavid du Colombier fprint(2, "xmr: hungup\n"); 733e12c5d1SDavid du Colombier exits("hangup"); 743e12c5d1SDavid du Colombier } 753e12c5d1SDavid du Colombier } 763e12c5d1SDavid du Colombier 773e12c5d1SDavid du Colombier int 783e12c5d1SDavid du Colombier readupto(uchar *a, int len) 793e12c5d1SDavid du Colombier { 803e12c5d1SDavid du Colombier int n; 813e12c5d1SDavid du Colombier int sofar; 823e12c5d1SDavid du Colombier 833e12c5d1SDavid du Colombier for(sofar = 0; sofar < len; sofar += n){ 843e12c5d1SDavid du Colombier n = read(0, a, len-sofar); 853e12c5d1SDavid du Colombier if(n <= 0){ 863e12c5d1SDavid du Colombier send(Nak); 873e12c5d1SDavid du Colombier return sofar; 883e12c5d1SDavid du Colombier } 893e12c5d1SDavid du Colombier if(*a == Eot || *a == Cancel) 903e12c5d1SDavid du Colombier return sofar + n; 913e12c5d1SDavid du Colombier a += n; 923e12c5d1SDavid du Colombier } 933e12c5d1SDavid du Colombier return sofar; 943e12c5d1SDavid du Colombier 953e12c5d1SDavid du Colombier } 963e12c5d1SDavid du Colombier 973e12c5d1SDavid du Colombier int 983e12c5d1SDavid du Colombier receive(int fd, uchar seqno) 993e12c5d1SDavid du Colombier { 1003e12c5d1SDavid du Colombier uchar buf[128+4]; 1013e12c5d1SDavid du Colombier uchar sum; 1023e12c5d1SDavid du Colombier uchar *p; 1033e12c5d1SDavid du Colombier int n; 1043e12c5d1SDavid du Colombier int tries; 1053e12c5d1SDavid du Colombier int have; 1063e12c5d1SDavid du Colombier 1073e12c5d1SDavid du Colombier for(have = 0, tries = 0;; tries++){ 1083e12c5d1SDavid du Colombier if(debug) 1093e12c5d1SDavid du Colombier fprint(dfd, "have == %d\n", have); 1103e12c5d1SDavid du Colombier if(tries > 10){ 1113e12c5d1SDavid du Colombier fprint(2, "xmr: timed out\n"); 1123e12c5d1SDavid du Colombier if(debug) 1133e12c5d1SDavid du Colombier close(dfd); 1143e12c5d1SDavid du Colombier exits("timeout"); 1153e12c5d1SDavid du Colombier } 1163e12c5d1SDavid du Colombier 1173e12c5d1SDavid du Colombier /* try to gather up a block */ 1183e12c5d1SDavid du Colombier alarm(15*1000); 1193e12c5d1SDavid du Colombier n = readupto(&buf[have], 132-have); 1203e12c5d1SDavid du Colombier alarm(0); 1213e12c5d1SDavid du Colombier have += n; 1223e12c5d1SDavid du Colombier if(have){ 1233e12c5d1SDavid du Colombier switch(buf[0]){ 1243e12c5d1SDavid du Colombier case Eot: 1253e12c5d1SDavid du Colombier send(Ack); 1263e12c5d1SDavid du Colombier return -1; 1273e12c5d1SDavid du Colombier case Cancel: 1283e12c5d1SDavid du Colombier fprint(2, "xmr: transfer aborted by sender\n"); 1293e12c5d1SDavid du Colombier exits("cancel"); 1303e12c5d1SDavid du Colombier } 1313e12c5d1SDavid du Colombier } 1323e12c5d1SDavid du Colombier if(have != 132) 1333e12c5d1SDavid du Colombier continue; 1343e12c5d1SDavid du Colombier 1353e12c5d1SDavid du Colombier /* checksum */ 1363e12c5d1SDavid du Colombier for(p = buf, sum = 0; p < &buf[128+3]; p++) 1373e12c5d1SDavid du Colombier sum += *p; 1383e12c5d1SDavid du Colombier 1393e12c5d1SDavid du Colombier /* If invalid block, resynchronize */ 1403e12c5d1SDavid du Colombier if(buf[0] != Soh || buf[2] != (255-buf[1]) || sum != buf[131]){ 1413e12c5d1SDavid du Colombier if(debug){ 1423e12c5d1SDavid du Colombier fprint(dfd, "resync %c %d %d %ux %ux\n", buf[0], 1433e12c5d1SDavid du Colombier buf[1], buf[2], sum, buf[131]); 144*7dd7cddfSDavid du Colombier fprint(dfd, "%*.*s\n", 128, 128, (char*)buf+3); 1453e12c5d1SDavid du Colombier } 1463e12c5d1SDavid du Colombier p = memchr(buf+1, Soh, 131); 1473e12c5d1SDavid du Colombier if(p){ 1483e12c5d1SDavid du Colombier have = 132-(p-buf); 1493e12c5d1SDavid du Colombier memmove(buf, p, have); 1503e12c5d1SDavid du Colombier } else 1513e12c5d1SDavid du Colombier have = 0; 1523e12c5d1SDavid du Colombier continue; 1533e12c5d1SDavid du Colombier } 1543e12c5d1SDavid du Colombier 1553e12c5d1SDavid du Colombier /* it's probably a real block, so dump it if there's an error */ 1563e12c5d1SDavid du Colombier have = 0; 1573e12c5d1SDavid du Colombier 1583e12c5d1SDavid du Colombier /* if this is the last block, ack */ 1593e12c5d1SDavid du Colombier if(buf[1] == seqno-1){ 1603e12c5d1SDavid du Colombier tries = 0; 1613e12c5d1SDavid du Colombier send(Ack); 1623e12c5d1SDavid du Colombier }else if(buf[1] == seqno){ 1633e12c5d1SDavid du Colombier if(debug) 1643e12c5d1SDavid du Colombier fprint(dfd, "Ack\n"); 1653e12c5d1SDavid du Colombier send(Ack); 1663e12c5d1SDavid du Colombier if(write(fd, buf+3, 128) != 128){ 1673e12c5d1SDavid du Colombier fprint(2, "xmr: abort, error writing file\n"); 1683e12c5d1SDavid du Colombier exits("write"); 1693e12c5d1SDavid du Colombier } 1703e12c5d1SDavid du Colombier return 0; 1713e12c5d1SDavid du Colombier } else { 1723e12c5d1SDavid du Colombier send(Nak); 1733e12c5d1SDavid du Colombier } 1743e12c5d1SDavid du Colombier } 1753e12c5d1SDavid du Colombier return -1; 1763e12c5d1SDavid du Colombier } 1773e12c5d1SDavid du Colombier 1783e12c5d1SDavid du Colombier int 1793e12c5d1SDavid du Colombier notifyf(void *a, char *msg) 1803e12c5d1SDavid du Colombier { 1813e12c5d1SDavid du Colombier USED(a); 1823e12c5d1SDavid du Colombier if(strcmp(msg, "alarm") == 0) 1833e12c5d1SDavid du Colombier return 1; 1843e12c5d1SDavid du Colombier return 0; 1853e12c5d1SDavid du Colombier } 186