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