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