xref: /plan9-contrib/sys/src/cmd/con/xms.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include <u.h>
2 #include <libc.h>
3 #include <ctype.h>
4 
5 enum {
6 	Soh=	0x1,
7 	Eot=	0x4,
8 	Ack=	0x6,
9 	Nak=	0x15,
10 	Cancel=	0x18,
11 };
12 
13 int send(uchar*, int);
14 int notifyf(void*, char*);
15 
16 int debug;
17 
18 void
19 errorout(int ctl, int bytes)
20 {
21 	uchar buf[2];
22 
23 	buf[0] = Cancel;
24 	write(1, buf, 1);
25 	fprint(2, "\nxms: gave up after %d bytes\n", bytes);
26 	write(ctl, "rawoff", 6);
27 	exits("cancel");
28 }
29 
30 void
31 main(int argc, char **argv)
32 {
33 	uchar c;
34 	uchar buf[128+4];
35 	uchar seqno;
36 	int fd, ctl;
37 	long n;
38 	int sum;
39 	uchar *p;
40 	int bytes;
41 
42 	ARGBEGIN{
43 	case 'd':
44 		debug = 1;
45 		break;
46 	}ARGEND
47 
48 	if(argc != 1){
49 		fprint(2, "usage: xms filename\n");
50 		exits("usage");
51 	}
52 	fd = open(argv[0], OREAD);
53 	if(fd < 0){
54 		perror("xms");
55 		exits("open");
56 	}
57 
58 	ctl = open("/dev/consctl", OWRITE);
59 	if(ctl < 0){
60 		perror("xms");
61 		exits("consctl");
62 	}
63 	write(ctl, "rawon", 5);
64 
65 	/* give the other side a 30 seconds to signal ready */
66 	atnotify(notifyf, 1);
67 	alarm(30*1000);
68 	for(;;){
69 		if(read(0, &c, 1) != 1){
70 			fprint(2, "xms: timeout\n");
71 			exits("timeout");
72 		}
73 		c = c & 0x7f;
74 		if(c == Nak)
75 			break;
76 	}
77 	alarm(0);
78 
79 	/* send the file in 128 byte chunks */
80 	for(bytes = 0, seqno = 1; ; bytes += n, seqno++){
81 		n = read(fd, buf+3, 128);
82 		if(n < 0)
83 			exits("read");
84 		if(n == 0)
85 			break;
86 		if(n < 128)
87 			memset(&buf[n+3], 0, 128-n);
88 		buf[0] = Soh;
89 		buf[1] = seqno;
90 		buf[2] = 255 - seqno;
91 
92 		/* calculate checksum and stuff into last byte */
93 		sum = 0;
94 		for(p = buf; p < &buf[128+3]; p++)
95 			sum += *p;
96 		buf[131] = sum;
97 
98 		if(send(buf, 132) < 0)
99 			errorout(ctl, bytes);
100 	}
101 
102 	/* tell other side we're done */
103 	buf[0] = Eot;
104 	if(send(buf, 1) < 0)
105 		errorout(ctl, bytes);
106 
107 	fprint(2, "xms: %d bytes transmitted\n", bytes);
108 	write(ctl, "rawoff", 6);
109 	exits(0);
110 }
111 
112 /*
113  *  send a message till it's acked or we give up
114  */
115 int
116 send(uchar *buf, int len)
117 {
118 	int tries;
119 	int n;
120 	uchar c;
121 
122 	for(tries = 0;; tries++, sleep(2*1000)){
123 		if(tries == 10)
124 			return -1;
125 		if(write(1, buf, len) != len)
126 			return -1;
127 
128 		alarm(30*1000);
129 		n = read(0, &c, 1);
130 		alarm(0);
131 		if(debug) switch(c){
132 		case Soh:
133 			fprint(2, " Soh");
134 			break;
135 		case Eot:
136 			fprint(2, " Eot");
137 			break;
138 		case Ack:
139 			fprint(2, " Ack");
140 			break;
141 		case Nak:
142 			fprint(2, " Nak");
143 			break;
144 		case Cancel:
145 			fprint(2, "\nremote Cancel\n");
146 			return -1;
147 		default:
148 			if(isprint(c))
149 				fprint(2, "%c", c);
150 			else
151 				fprint(2, " \0%o", c);
152 		}
153 		c = c & 0x7f;
154 		if(n == 1 && c == Ack)
155 			break;
156 	}
157 	return 0;
158 }
159 
160 int
161 notifyf(void *a, char *msg)
162 {
163 	USED(a);
164 	if(strcmp(msg, "alarm") == 0)
165 		return 1;
166 	return 0;
167 }
168