183 lines
2.8 KiB
C
183 lines
2.8 KiB
C
#include <u.h>
|
|
#include <libc.h>
|
|
|
|
enum {
|
|
Soh= 0x1,
|
|
Eot= 0x4,
|
|
Ack= 0x6,
|
|
Nak= 0x15,
|
|
Cancel= 0x18,
|
|
};
|
|
|
|
int notifyf(void*, char*);
|
|
int readupto(uchar*, int);
|
|
int receive(int, uchar);
|
|
void send(int);
|
|
|
|
int debug, dfd;
|
|
|
|
void
|
|
main(int argc, char **argv)
|
|
{
|
|
int fd;
|
|
uchar seqno;
|
|
ulong bytes;
|
|
|
|
ARGBEGIN {
|
|
case 'd':
|
|
dfd = 2;
|
|
debug = 1;
|
|
break;
|
|
} ARGEND
|
|
|
|
if(argc != 1){
|
|
fprint(2, "usage: xmr filename\n");
|
|
exits("usage");
|
|
}
|
|
fd = open("/dev/consctl", OWRITE);
|
|
if(fd >= 0)
|
|
write(fd, "rawon", 5);
|
|
fd = create(argv[0], ORDWR, 0666);
|
|
if(fd < 0){
|
|
perror("xmr: create");
|
|
exits("create");
|
|
}
|
|
|
|
atnotify(notifyf, 1);
|
|
send(Nak);
|
|
|
|
/*
|
|
* keep receiving till the other side gives up
|
|
*/
|
|
bytes = 0;
|
|
for(seqno = 1; ; seqno++){
|
|
if(receive(fd, seqno) == -1)
|
|
break;
|
|
bytes += 128;
|
|
}
|
|
fprint(2, "xmr: received %ld bytes\n", bytes);
|
|
exits(0);
|
|
}
|
|
|
|
void
|
|
send(int byte)
|
|
{
|
|
uchar c;
|
|
|
|
c = byte;
|
|
if(write(1, &c, 1) != 1){
|
|
fprint(2, "xmr: hungup\n");
|
|
exits("hangup");
|
|
}
|
|
}
|
|
|
|
int
|
|
readupto(uchar *a, int len)
|
|
{
|
|
int n;
|
|
int sofar;
|
|
|
|
for(sofar = 0; sofar < len; sofar += n){
|
|
n = read(0, a, len-sofar);
|
|
if(n <= 0){
|
|
send(Nak);
|
|
return sofar;
|
|
}
|
|
if(*a == Eot || *a == Cancel)
|
|
return sofar + n;
|
|
a += n;
|
|
}
|
|
return sofar;
|
|
|
|
}
|
|
|
|
int
|
|
receive(int fd, uchar seqno)
|
|
{
|
|
uchar buf[128+4];
|
|
uchar sum;
|
|
uchar *p;
|
|
int n;
|
|
int tries;
|
|
int have;
|
|
|
|
for(have = 0, tries = 0;; tries++){
|
|
if(debug)
|
|
fprint(dfd, "have == %d\n", have);
|
|
if(tries > 10){
|
|
fprint(2, "xmr: timed out\n");
|
|
if(debug)
|
|
close(dfd);
|
|
exits("timeout");
|
|
}
|
|
|
|
/* try to gather up a block */
|
|
alarm(15*1000);
|
|
n = readupto(&buf[have], 132-have);
|
|
alarm(0);
|
|
have += n;
|
|
if(have){
|
|
switch(buf[0]){
|
|
case Eot:
|
|
send(Ack);
|
|
return -1;
|
|
case Cancel:
|
|
fprint(2, "xmr: transfer aborted by sender\n");
|
|
exits("cancel");
|
|
}
|
|
}
|
|
if(have != 132)
|
|
continue;
|
|
|
|
/* checksum */
|
|
for(p = buf, sum = 0; p < &buf[128+3]; p++)
|
|
sum += *p;
|
|
|
|
/* If invalid block, resynchronize */
|
|
if(buf[0] != Soh || buf[2] != (255-buf[1]) || sum != buf[131]){
|
|
if(debug){
|
|
fprint(dfd, "resync %2.2ux %d %d %ux %ux\n", buf[0],
|
|
buf[1], buf[2], sum, buf[131]);
|
|
write(dfd, (char*)buf+3, 128);
|
|
fprint(dfd, "\n");
|
|
}
|
|
p = memchr(buf+1, Soh, 131);
|
|
if(p){
|
|
have = 132-(p-buf);
|
|
memmove(buf, p, have);
|
|
} else
|
|
have = 0;
|
|
continue;
|
|
}
|
|
|
|
/* it's probably a real block, so dump it if there's an error */
|
|
have = 0;
|
|
|
|
/* if this is the last block, ack */
|
|
if(buf[1] == seqno-1){
|
|
tries = 0;
|
|
send(Ack);
|
|
}else if(buf[1] == seqno){
|
|
if(debug)
|
|
fprint(dfd, "Ack\n");
|
|
send(Ack);
|
|
if(write(fd, buf+3, 128) != 128){
|
|
fprint(2, "xmr: abort, error writing file\n");
|
|
exits("write");
|
|
}
|
|
return 0;
|
|
} else {
|
|
send(Nak);
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
notifyf(void *a, char *msg)
|
|
{
|
|
USED(a);
|
|
if(strcmp(msg, "alarm") == 0)
|
|
return 1;
|
|
return 0;
|
|
}
|