xref: /plan9/sys/src/cmd/con/xmr.c (revision b85a83648eec38fe82b6f00adfd7828ceec5ee8d)
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
main(int argc,char ** argv)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);
38*80ee5cbfSDavid du Colombier 	if(fd >= 0)
393e12c5d1SDavid du Colombier 		write(fd, "rawon", 5);
403e12c5d1SDavid du Colombier 	fd = create(argv[0], ORDWR, 0666);
413e12c5d1SDavid du Colombier 	if(fd < 0){
42219b2ee8SDavid du Colombier 		perror("xmr: create");
43219b2ee8SDavid du Colombier 		exits("create");
443e12c5d1SDavid du Colombier 	}
453e12c5d1SDavid du Colombier 
463e12c5d1SDavid du Colombier 	atnotify(notifyf, 1);
473e12c5d1SDavid du Colombier 	send(Nak);
483e12c5d1SDavid du Colombier 
493e12c5d1SDavid du Colombier 	/*
503e12c5d1SDavid du Colombier 	 *  keep receiving till the other side gives up
513e12c5d1SDavid du Colombier 	 */
523e12c5d1SDavid du Colombier 	bytes = 0;
533e12c5d1SDavid du Colombier 	for(seqno = 1; ; seqno++){
543e12c5d1SDavid du Colombier 		if(receive(fd, seqno) == -1)
553e12c5d1SDavid du Colombier 			break;
563e12c5d1SDavid du Colombier 		bytes += 128;
573e12c5d1SDavid du Colombier 	}
587dd7cddfSDavid du Colombier 	fprint(2, "xmr: received %ld bytes\n", bytes);
593e12c5d1SDavid du Colombier 	exits(0);
603e12c5d1SDavid du Colombier }
613e12c5d1SDavid du Colombier 
623e12c5d1SDavid du Colombier void
send(int byte)633e12c5d1SDavid du Colombier send(int byte)
643e12c5d1SDavid du Colombier {
653e12c5d1SDavid du Colombier 	uchar c;
663e12c5d1SDavid du Colombier 
673e12c5d1SDavid du Colombier 	c = byte;
683e12c5d1SDavid du Colombier 	if(write(1, &c, 1) != 1){
693e12c5d1SDavid du Colombier 		fprint(2, "xmr: hungup\n");
703e12c5d1SDavid du Colombier 		exits("hangup");
713e12c5d1SDavid du Colombier 	}
723e12c5d1SDavid du Colombier }
733e12c5d1SDavid du Colombier 
743e12c5d1SDavid du Colombier int
readupto(uchar * a,int len)753e12c5d1SDavid du Colombier readupto(uchar *a, int len)
763e12c5d1SDavid du Colombier {
773e12c5d1SDavid du Colombier 	int n;
783e12c5d1SDavid du Colombier 	int sofar;
793e12c5d1SDavid du Colombier 
803e12c5d1SDavid du Colombier 	for(sofar = 0; sofar < len; sofar += n){
813e12c5d1SDavid du Colombier 		n = read(0, a, len-sofar);
823e12c5d1SDavid du Colombier 		if(n <= 0){
833e12c5d1SDavid du Colombier 			send(Nak);
843e12c5d1SDavid du Colombier 			return sofar;
853e12c5d1SDavid du Colombier 		}
863e12c5d1SDavid du Colombier 		if(*a == Eot || *a == Cancel)
873e12c5d1SDavid du Colombier 			return sofar + n;
883e12c5d1SDavid du Colombier 		a += n;
893e12c5d1SDavid du Colombier 	}
903e12c5d1SDavid du Colombier 	return sofar;
913e12c5d1SDavid du Colombier 
923e12c5d1SDavid du Colombier }
933e12c5d1SDavid du Colombier 
943e12c5d1SDavid du Colombier int
receive(int fd,uchar seqno)953e12c5d1SDavid du Colombier receive(int fd, uchar seqno)
963e12c5d1SDavid du Colombier {
973e12c5d1SDavid du Colombier 	uchar buf[128+4];
983e12c5d1SDavid du Colombier 	uchar sum;
993e12c5d1SDavid du Colombier 	uchar *p;
1003e12c5d1SDavid du Colombier 	int n;
1013e12c5d1SDavid du Colombier 	int tries;
1023e12c5d1SDavid du Colombier 	int have;
1033e12c5d1SDavid du Colombier 
1043e12c5d1SDavid du Colombier 	for(have = 0, tries = 0;; tries++){
1053e12c5d1SDavid du Colombier 		if(debug)
1063e12c5d1SDavid du Colombier 			fprint(dfd, "have == %d\n", have);
1073e12c5d1SDavid du Colombier 		if(tries > 10){
1083e12c5d1SDavid du Colombier 			fprint(2, "xmr: timed out\n");
1093e12c5d1SDavid du Colombier 			if(debug)
1103e12c5d1SDavid du Colombier 				close(dfd);
1113e12c5d1SDavid du Colombier 			exits("timeout");
1123e12c5d1SDavid du Colombier 		}
1133e12c5d1SDavid du Colombier 
1143e12c5d1SDavid du Colombier 		/* try to gather up a block */
1153e12c5d1SDavid du Colombier 		alarm(15*1000);
1163e12c5d1SDavid du Colombier 		n = readupto(&buf[have], 132-have);
1173e12c5d1SDavid du Colombier 		alarm(0);
1183e12c5d1SDavid du Colombier 		have += n;
1193e12c5d1SDavid du Colombier 		if(have){
1203e12c5d1SDavid du Colombier 			switch(buf[0]){
1213e12c5d1SDavid du Colombier 			case Eot:
1223e12c5d1SDavid du Colombier 				send(Ack);
1233e12c5d1SDavid du Colombier 				return -1;
1243e12c5d1SDavid du Colombier 			case Cancel:
1253e12c5d1SDavid du Colombier 				fprint(2, "xmr: transfer aborted by sender\n");
1263e12c5d1SDavid du Colombier 				exits("cancel");
1273e12c5d1SDavid du Colombier 			}
1283e12c5d1SDavid du Colombier 		}
1293e12c5d1SDavid du Colombier 		if(have != 132)
1303e12c5d1SDavid du Colombier 			continue;
1313e12c5d1SDavid du Colombier 
1323e12c5d1SDavid du Colombier 		/* checksum */
1333e12c5d1SDavid du Colombier 		for(p = buf, sum = 0; p < &buf[128+3]; p++)
1343e12c5d1SDavid du Colombier 			sum += *p;
1353e12c5d1SDavid du Colombier 
1363e12c5d1SDavid du Colombier 		/* If invalid block, resynchronize */
1373e12c5d1SDavid du Colombier 		if(buf[0] != Soh || buf[2] != (255-buf[1]) || sum != buf[131]){
1383e12c5d1SDavid du Colombier 			if(debug){
139*80ee5cbfSDavid du Colombier 				fprint(dfd, "resync %2.2ux %d %d %ux %ux\n", buf[0],
1403e12c5d1SDavid du Colombier 					buf[1], buf[2], sum, buf[131]);
14159cc4ca5SDavid du Colombier 				write(dfd, (char*)buf+3, 128);
14259cc4ca5SDavid du Colombier 				fprint(dfd, "\n");
1433e12c5d1SDavid du Colombier 			}
1443e12c5d1SDavid du Colombier 			p = memchr(buf+1, Soh, 131);
1453e12c5d1SDavid du Colombier 			if(p){
1463e12c5d1SDavid du Colombier 				have = 132-(p-buf);
1473e12c5d1SDavid du Colombier 				memmove(buf, p, have);
1483e12c5d1SDavid du Colombier 			} else
1493e12c5d1SDavid du Colombier 				have = 0;
1503e12c5d1SDavid du Colombier 			continue;
1513e12c5d1SDavid du Colombier 		}
1523e12c5d1SDavid du Colombier 
1533e12c5d1SDavid du Colombier 		/* it's probably a real block, so dump it if there's an error */
1543e12c5d1SDavid du Colombier 		have = 0;
1553e12c5d1SDavid du Colombier 
1563e12c5d1SDavid du Colombier 		/* if this is the last block, ack */
1573e12c5d1SDavid du Colombier 		if(buf[1] == seqno-1){
1583e12c5d1SDavid du Colombier 			tries = 0;
1593e12c5d1SDavid du Colombier 			send(Ack);
1603e12c5d1SDavid du Colombier 		}else if(buf[1] == seqno){
1613e12c5d1SDavid du Colombier 			if(debug)
1623e12c5d1SDavid du Colombier 				fprint(dfd, "Ack\n");
1633e12c5d1SDavid du Colombier 			send(Ack);
1643e12c5d1SDavid du Colombier 			if(write(fd, buf+3, 128) != 128){
1653e12c5d1SDavid du Colombier 				fprint(2, "xmr: abort, error writing file\n");
1663e12c5d1SDavid du Colombier 				exits("write");
1673e12c5d1SDavid du Colombier 			}
1683e12c5d1SDavid du Colombier 			return 0;
1693e12c5d1SDavid du Colombier 		} else {
1703e12c5d1SDavid du Colombier 			send(Nak);
1713e12c5d1SDavid du Colombier 		}
1723e12c5d1SDavid du Colombier 	}
1733e12c5d1SDavid du Colombier }
1743e12c5d1SDavid du Colombier 
1753e12c5d1SDavid du Colombier int
notifyf(void * a,char * msg)1763e12c5d1SDavid du Colombier notifyf(void *a, char *msg)
1773e12c5d1SDavid du Colombier {
1783e12c5d1SDavid du Colombier 	USED(a);
1793e12c5d1SDavid du Colombier 	if(strcmp(msg, "alarm") == 0)
1803e12c5d1SDavid du Colombier 		return 1;
1813e12c5d1SDavid du Colombier 	return 0;
1823e12c5d1SDavid du Colombier }
183