Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
		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
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
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
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
176
notifyf(void *a, char *msg)
177
{
178
	USED(a);
179
	if(strcmp(msg, "alarm") == 0)
180
		return 1;
181
	return 0;
182
}