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
main(int argc,char ** argv)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
send(int byte)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
readupto(uchar * a,int len)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
receive(int fd,uchar seqno)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
notifyf(void * a,char * msg)176 notifyf(void *a, char *msg)
177 {
178 USED(a);
179 if(strcmp(msg, "alarm") == 0)
180 return 1;
181 return 0;
182 }
183