xref: /plan9-contrib/sys/src/cmd/con/xmr.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
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