1 #include <u.h> 2 #include <libc.h> 3 4 enum { 5 Soh= 0x1, 6 Eot= 0x4, 7 Ack= 0x6, 8 Nak= 0x15, 9 Cancel= 0x18, 10 }; 11 12 int notifyf(void*, char*); 13 int readupto(uchar*, int); 14 int receive(int, uchar); 15 void send(int); 16 17 int debug, dfd; 18 19 void 20 main(int argc, char **argv) 21 { 22 int fd; 23 uchar seqno; 24 ulong bytes; 25 26 ARGBEGIN { 27 case 'd': 28 dfd = 2; 29 debug = 1; 30 break; 31 } ARGEND 32 33 if(argc != 1){ 34 fprint(2, "usage: xmr filename\n"); 35 exits("usage"); 36 } 37 fd = open("/dev/consctl", OWRITE); 38 if(fd >= 0) 39 write(fd, "rawon", 5); 40 fd = create(argv[0], ORDWR, 0666); 41 if(fd < 0){ 42 perror("xmr: create"); 43 exits("create"); 44 } 45 46 atnotify(notifyf, 1); 47 send(Nak); 48 49 /* 50 * keep receiving till the other side gives up 51 */ 52 bytes = 0; 53 for(seqno = 1; ; seqno++){ 54 if(receive(fd, seqno) == -1) 55 break; 56 bytes += 128; 57 } 58 fprint(2, "xmr: received %ld bytes\n", bytes); 59 exits(0); 60 } 61 62 void 63 send(int byte) 64 { 65 uchar c; 66 67 c = byte; 68 if(write(1, &c, 1) != 1){ 69 fprint(2, "xmr: hungup\n"); 70 exits("hangup"); 71 } 72 } 73 74 int 75 readupto(uchar *a, int len) 76 { 77 int n; 78 int sofar; 79 80 for(sofar = 0; sofar < len; sofar += n){ 81 n = read(0, a, len-sofar); 82 if(n <= 0){ 83 send(Nak); 84 return sofar; 85 } 86 if(*a == Eot || *a == Cancel) 87 return sofar + n; 88 a += n; 89 } 90 return sofar; 91 92 } 93 94 int 95 receive(int fd, uchar seqno) 96 { 97 uchar buf[128+4]; 98 uchar sum; 99 uchar *p; 100 int n; 101 int tries; 102 int have; 103 104 for(have = 0, tries = 0;; tries++){ 105 if(debug) 106 fprint(dfd, "have == %d\n", have); 107 if(tries > 10){ 108 fprint(2, "xmr: timed out\n"); 109 if(debug) 110 close(dfd); 111 exits("timeout"); 112 } 113 114 /* try to gather up a block */ 115 alarm(15*1000); 116 n = readupto(&buf[have], 132-have); 117 alarm(0); 118 have += n; 119 if(have){ 120 switch(buf[0]){ 121 case Eot: 122 send(Ack); 123 return -1; 124 case Cancel: 125 fprint(2, "xmr: transfer aborted by sender\n"); 126 exits("cancel"); 127 } 128 } 129 if(have != 132) 130 continue; 131 132 /* checksum */ 133 for(p = buf, sum = 0; p < &buf[128+3]; p++) 134 sum += *p; 135 136 /* If invalid block, resynchronize */ 137 if(buf[0] != Soh || buf[2] != (255-buf[1]) || sum != buf[131]){ 138 if(debug){ 139 fprint(dfd, "resync %2.2ux %d %d %ux %ux\n", buf[0], 140 buf[1], buf[2], sum, buf[131]); 141 write(dfd, (char*)buf+3, 128); 142 fprint(dfd, "\n"); 143 } 144 p = memchr(buf+1, Soh, 131); 145 if(p){ 146 have = 132-(p-buf); 147 memmove(buf, p, have); 148 } else 149 have = 0; 150 continue; 151 } 152 153 /* it's probably a real block, so dump it if there's an error */ 154 have = 0; 155 156 /* if this is the last block, ack */ 157 if(buf[1] == seqno-1){ 158 tries = 0; 159 send(Ack); 160 }else if(buf[1] == seqno){ 161 if(debug) 162 fprint(dfd, "Ack\n"); 163 send(Ack); 164 if(write(fd, buf+3, 128) != 128){ 165 fprint(2, "xmr: abort, error writing file\n"); 166 exits("write"); 167 } 168 return 0; 169 } else { 170 send(Nak); 171 } 172 } 173 } 174 175 int 176 notifyf(void *a, char *msg) 177 { 178 USED(a); 179 if(strcmp(msg, "alarm") == 0) 180 return 1; 181 return 0; 182 } 183