xref: /plan9-contrib/sys/src/cmd/con/xmr.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier 
43e12c5d1SDavid du Colombier enum {
53e12c5d1SDavid du Colombier 	Soh=	0x1,
63e12c5d1SDavid du Colombier 	Eot=	0x4,
73e12c5d1SDavid du Colombier 	Ack=	0x6,
83e12c5d1SDavid du Colombier 	Nak=	0x15,
93e12c5d1SDavid du Colombier 	Cancel=	0x18,
103e12c5d1SDavid du Colombier };
113e12c5d1SDavid du Colombier 
123e12c5d1SDavid du Colombier int notifyf(void*, char*);
133e12c5d1SDavid du Colombier int readupto(uchar*, int);
143e12c5d1SDavid du Colombier int receive(int, uchar);
153e12c5d1SDavid du Colombier void send(int);
163e12c5d1SDavid du Colombier 
173e12c5d1SDavid du Colombier int debug, dfd;
183e12c5d1SDavid du Colombier 
193e12c5d1SDavid du Colombier void
203e12c5d1SDavid du Colombier main(int argc, char **argv)
213e12c5d1SDavid du Colombier {
223e12c5d1SDavid du Colombier 	int fd;
233e12c5d1SDavid du Colombier 	uchar seqno;
243e12c5d1SDavid du Colombier 	ulong bytes;
253e12c5d1SDavid du Colombier 
263e12c5d1SDavid du Colombier 	ARGBEGIN {
273e12c5d1SDavid du Colombier 	case 'd':
283e12c5d1SDavid du Colombier 		dfd = 2;
293e12c5d1SDavid du Colombier 		debug = 1;
303e12c5d1SDavid du Colombier 		break;
313e12c5d1SDavid du Colombier 	} ARGEND
323e12c5d1SDavid du Colombier 
333e12c5d1SDavid du Colombier 	if(argc != 1){
343e12c5d1SDavid du Colombier 		fprint(2, "usage: xmr filename\n");
353e12c5d1SDavid du Colombier 		exits("usage");
363e12c5d1SDavid du Colombier 	}
373e12c5d1SDavid du Colombier 	fd = open("/dev/consctl", OWRITE);
383e12c5d1SDavid du Colombier 	if(fd < 0){
39219b2ee8SDavid du Colombier 		perror("xmr: open consctl");
403e12c5d1SDavid du Colombier 		exits("consctl");
413e12c5d1SDavid du Colombier 	}
423e12c5d1SDavid du Colombier 	write(fd, "rawon", 5);
433e12c5d1SDavid du Colombier 	fd = create(argv[0], ORDWR, 0666);
443e12c5d1SDavid du Colombier 	if(fd < 0){
45219b2ee8SDavid du Colombier 		perror("xmr: create");
46219b2ee8SDavid du Colombier 		exits("create");
473e12c5d1SDavid du Colombier 	}
483e12c5d1SDavid du Colombier 
493e12c5d1SDavid du Colombier 	atnotify(notifyf, 1);
503e12c5d1SDavid du Colombier 	send(Nak);
513e12c5d1SDavid du Colombier 
523e12c5d1SDavid du Colombier 	/*
533e12c5d1SDavid du Colombier 	 *  keep receiving till the other side gives up
543e12c5d1SDavid du Colombier 	 */
553e12c5d1SDavid du Colombier 	bytes = 0;
563e12c5d1SDavid du Colombier 	for(seqno = 1; ; seqno++){
573e12c5d1SDavid du Colombier 		if(receive(fd, seqno) == -1)
583e12c5d1SDavid du Colombier 			break;
593e12c5d1SDavid du Colombier 		bytes += 128;
603e12c5d1SDavid du Colombier 	}
61*7dd7cddfSDavid du Colombier 	fprint(2, "xmr: received %ld bytes\n", bytes);
623e12c5d1SDavid du Colombier 	exits(0);
633e12c5d1SDavid du Colombier }
643e12c5d1SDavid du Colombier 
653e12c5d1SDavid du Colombier void
663e12c5d1SDavid du Colombier send(int byte)
673e12c5d1SDavid du Colombier {
683e12c5d1SDavid du Colombier 	uchar c;
693e12c5d1SDavid du Colombier 
703e12c5d1SDavid du Colombier 	c = byte;
713e12c5d1SDavid du Colombier 	if(write(1, &c, 1) != 1){
723e12c5d1SDavid du Colombier 		fprint(2, "xmr: hungup\n");
733e12c5d1SDavid du Colombier 		exits("hangup");
743e12c5d1SDavid du Colombier 	}
753e12c5d1SDavid du Colombier }
763e12c5d1SDavid du Colombier 
773e12c5d1SDavid du Colombier int
783e12c5d1SDavid du Colombier readupto(uchar *a, int len)
793e12c5d1SDavid du Colombier {
803e12c5d1SDavid du Colombier 	int n;
813e12c5d1SDavid du Colombier 	int sofar;
823e12c5d1SDavid du Colombier 
833e12c5d1SDavid du Colombier 	for(sofar = 0; sofar < len; sofar += n){
843e12c5d1SDavid du Colombier 		n = read(0, a, len-sofar);
853e12c5d1SDavid du Colombier 		if(n <= 0){
863e12c5d1SDavid du Colombier 			send(Nak);
873e12c5d1SDavid du Colombier 			return sofar;
883e12c5d1SDavid du Colombier 		}
893e12c5d1SDavid du Colombier 		if(*a == Eot || *a == Cancel)
903e12c5d1SDavid du Colombier 			return sofar + n;
913e12c5d1SDavid du Colombier 		a += n;
923e12c5d1SDavid du Colombier 	}
933e12c5d1SDavid du Colombier 	return sofar;
943e12c5d1SDavid du Colombier 
953e12c5d1SDavid du Colombier }
963e12c5d1SDavid du Colombier 
973e12c5d1SDavid du Colombier int
983e12c5d1SDavid du Colombier receive(int fd, uchar seqno)
993e12c5d1SDavid du Colombier {
1003e12c5d1SDavid du Colombier 	uchar buf[128+4];
1013e12c5d1SDavid du Colombier 	uchar sum;
1023e12c5d1SDavid du Colombier 	uchar *p;
1033e12c5d1SDavid du Colombier 	int n;
1043e12c5d1SDavid du Colombier 	int tries;
1053e12c5d1SDavid du Colombier 	int have;
1063e12c5d1SDavid du Colombier 
1073e12c5d1SDavid du Colombier 	for(have = 0, tries = 0;; tries++){
1083e12c5d1SDavid du Colombier 		if(debug)
1093e12c5d1SDavid du Colombier 			fprint(dfd, "have == %d\n", have);
1103e12c5d1SDavid du Colombier 		if(tries > 10){
1113e12c5d1SDavid du Colombier 			fprint(2, "xmr: timed out\n");
1123e12c5d1SDavid du Colombier 			if(debug)
1133e12c5d1SDavid du Colombier 				close(dfd);
1143e12c5d1SDavid du Colombier 			exits("timeout");
1153e12c5d1SDavid du Colombier 		}
1163e12c5d1SDavid du Colombier 
1173e12c5d1SDavid du Colombier 		/* try to gather up a block */
1183e12c5d1SDavid du Colombier 		alarm(15*1000);
1193e12c5d1SDavid du Colombier 		n = readupto(&buf[have], 132-have);
1203e12c5d1SDavid du Colombier 		alarm(0);
1213e12c5d1SDavid du Colombier 		have += n;
1223e12c5d1SDavid du Colombier 		if(have){
1233e12c5d1SDavid du Colombier 			switch(buf[0]){
1243e12c5d1SDavid du Colombier 			case Eot:
1253e12c5d1SDavid du Colombier 				send(Ack);
1263e12c5d1SDavid du Colombier 				return -1;
1273e12c5d1SDavid du Colombier 			case Cancel:
1283e12c5d1SDavid du Colombier 				fprint(2, "xmr: transfer aborted by sender\n");
1293e12c5d1SDavid du Colombier 				exits("cancel");
1303e12c5d1SDavid du Colombier 			}
1313e12c5d1SDavid du Colombier 		}
1323e12c5d1SDavid du Colombier 		if(have != 132)
1333e12c5d1SDavid du Colombier 			continue;
1343e12c5d1SDavid du Colombier 
1353e12c5d1SDavid du Colombier 		/* checksum */
1363e12c5d1SDavid du Colombier 		for(p = buf, sum = 0; p < &buf[128+3]; p++)
1373e12c5d1SDavid du Colombier 			sum += *p;
1383e12c5d1SDavid du Colombier 
1393e12c5d1SDavid du Colombier 		/* If invalid block, resynchronize */
1403e12c5d1SDavid du Colombier 		if(buf[0] != Soh || buf[2] != (255-buf[1]) || sum != buf[131]){
1413e12c5d1SDavid du Colombier 			if(debug){
1423e12c5d1SDavid du Colombier 				fprint(dfd, "resync %c %d %d %ux %ux\n", buf[0],
1433e12c5d1SDavid du Colombier 					buf[1], buf[2], sum, buf[131]);
144*7dd7cddfSDavid du Colombier 				fprint(dfd, "%*.*s\n", 128, 128, (char*)buf+3);
1453e12c5d1SDavid du Colombier 			}
1463e12c5d1SDavid du Colombier 			p = memchr(buf+1, Soh, 131);
1473e12c5d1SDavid du Colombier 			if(p){
1483e12c5d1SDavid du Colombier 				have = 132-(p-buf);
1493e12c5d1SDavid du Colombier 				memmove(buf, p, have);
1503e12c5d1SDavid du Colombier 			} else
1513e12c5d1SDavid du Colombier 				have = 0;
1523e12c5d1SDavid du Colombier 			continue;
1533e12c5d1SDavid du Colombier 		}
1543e12c5d1SDavid du Colombier 
1553e12c5d1SDavid du Colombier 		/* it's probably a real block, so dump it if there's an error */
1563e12c5d1SDavid du Colombier 		have = 0;
1573e12c5d1SDavid du Colombier 
1583e12c5d1SDavid du Colombier 		/* if this is the last block, ack */
1593e12c5d1SDavid du Colombier 		if(buf[1] == seqno-1){
1603e12c5d1SDavid du Colombier 			tries = 0;
1613e12c5d1SDavid du Colombier 			send(Ack);
1623e12c5d1SDavid du Colombier 		}else if(buf[1] == seqno){
1633e12c5d1SDavid du Colombier 			if(debug)
1643e12c5d1SDavid du Colombier 				fprint(dfd, "Ack\n");
1653e12c5d1SDavid du Colombier 			send(Ack);
1663e12c5d1SDavid du Colombier 			if(write(fd, buf+3, 128) != 128){
1673e12c5d1SDavid du Colombier 				fprint(2, "xmr: abort, error writing file\n");
1683e12c5d1SDavid du Colombier 				exits("write");
1693e12c5d1SDavid du Colombier 			}
1703e12c5d1SDavid du Colombier 			return 0;
1713e12c5d1SDavid du Colombier 		} else {
1723e12c5d1SDavid du Colombier 			send(Nak);
1733e12c5d1SDavid du Colombier 		}
1743e12c5d1SDavid du Colombier 	}
1753e12c5d1SDavid du Colombier 	return -1;
1763e12c5d1SDavid du Colombier }
1773e12c5d1SDavid du Colombier 
1783e12c5d1SDavid du Colombier int
1793e12c5d1SDavid du Colombier notifyf(void *a, char *msg)
1803e12c5d1SDavid du Colombier {
1813e12c5d1SDavid du Colombier 	USED(a);
1823e12c5d1SDavid du Colombier 	if(strcmp(msg, "alarm") == 0)
1833e12c5d1SDavid du Colombier 		return 1;
1843e12c5d1SDavid du Colombier 	return 0;
1853e12c5d1SDavid du Colombier }
186