home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
misc
/
volume32
/
xbbs
/
part04
/
checksum.c
< prev
Wrap
C/C++ Source or Header
|
1992-09-08
|
10KB
|
483 lines
/*
* A version of Ward Christensen's file transfer protocol for
* Unix System V or 4.2 bsd.
*
* Emmet P. Gray, ..!ihnp4!uiucuxc!fthood!egray, 16 Aug 85
*
* Modified by Sanford Zelkovitz 08/18/86
* Last modification date: 05/20/87
*/
#define SV
#undef BSD
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef SV
#include <termio.h>
#endif
#ifdef BSD
#include <sgtty.h>
#endif
#define MAXERRORS 10 /* max number of times to retry */
#define SECSIZE 128 /* CP/M sector, transmission block */
#define CPMEOF 26 /* End Of File (for CP/M) */
#define SOH 1 /* Start Of Header */
#define EOT 4 /* End Of Transmission */
#define ACK 6 /* ACKnowledge */
#define NAK 21 /* Negative AcKnowledge */
#define CAN 24 /* CANcel */
int synchron;
int exit_return;
unsigned char crc1, crc2;
#ifdef SV
struct termio ttyhold;
#endif
#ifdef BSD
struct sgttyb ttyhold;
#endif
main(argc, argv)
int argc;
char *argv[];
{
int msgstat;
char *tty, *ttyname();
struct stat stbuf;
exit_return=0;
if (argc != 3) {
usage();
exit(1);
}
tty = ttyname(1);
stat(tty, &stbuf);
msgstat = (stbuf.st_mode & 0777);
chmod(tty, 0600); /* mesg n */
#ifdef SV
ioctl(0, TCGETA, &ttyhold); /* get current settings */
#endif
#ifdef BSD
ioctl(0, TIOCGETP, &ttyhold);
#endif
switch (*argv[1]) {
case 'r':
recvfile(argv[2]);
break;
case 's':
sendfile(argv[2]);
break;
default:
usage();
}
#ifdef SV
ioctl(0, TCSETAF, &ttyhold); /* restore settings */
#endif
#ifdef BSD
ioctl(0, TIOCSETP, &ttyhold);
#endif
chmod(tty, msgstat); /* restore mesg status */
exit(exit_return);
}
/* send a file to the remote */
sendfile(tfile)
char *tfile;
{
FILE *fp;
unsigned char chr, checksum, block, sector[SECSIZE];
int i, mode, nbytes, errcount, size, speed;
long min, sec;
static int baud[15] = {0, 50, 75, 110, 134, 150, 200,
300, 600, 1200, 1800, 2400, 4800, 9600, 19200};
struct stat sbuf;
if (!(fp = fopen(tfile, "r"))) {
fprintf(stderr, "xmodem: Can't open '%s' for read\r\n", tfile);
exit_return=1;
return;
}
stat(tfile, &sbuf);
size = (sbuf.st_size / 128) + 1;
#ifdef SV
speed = baud[ttyhold.c_cflag & 017];
#endif
#ifdef BSD
speed = baud[ttyhold.sg_ispeed];
#endif
sec = size;
sec = sec * 128L * 11L / speed;
min = sec / 60L;
sec = sec - min * 60L;
printf("File open: %d records\r\n", size);
printf("Send time: %ld min, %ld sec at %d baud\r\n", min, sec, speed);
printf("To cancel: use CTRL-X numerous times\r\n");
printf("Waiting ready signal\r\n");
rawmode();
errcount = 0;
mode = 0;
block = 1;
while (errcount < MAXERRORS) {
chr = getchar_t();
if (chr == NAK) /* checksum mode */
break;
if (chr == 'C') { /* CRC mode */
mode = 1;
break;
}
errcount++;
}
if (errcount == MAXERRORS) {
sleep(3);
fprintf(stderr, "xmodem: Timed out on acknowledge\r\n");
exit_return=1;
return;
}
while (nbytes = fread(sector, sizeof(sector[0]), SECSIZE, fp)) {
if (nbytes < SECSIZE) { /* fill short sector */
for (i=nbytes; i < SECSIZE; i++)
sector[i] = CPMEOF;
}
errcount = 0;
while (errcount < MAXERRORS) {
putchar(SOH); /* the header */
putchar(block); /* the block number */
chr = ~block;
putchar(chr); /* it's complement */
checksum = 0;
crc1 = 0;
crc2 = 0;
for (i=0; i < SECSIZE; i++) {
putchar(sector[i]);
if (mode)
update_crc(sector[i]);
else
checksum += sector[i];
}
if (mode) {
update_crc(0);
update_crc(0);
putchar(crc1);
putchar(crc2);
}
else
putchar(checksum);
rec_loop:
chr = getchar_t();
if (chr == CAN) {
sleep(3);
exit_return=1;
fprintf(stderr,"\r\nxmodem: Abort request received\r\n");
return;
}
if (chr == ACK)
break; /* got it! */
if (chr != NAK) goto rec_loop; /* Noise on line? */
errcount++;
}
if (errcount == MAXERRORS) {
error();
exit_return=1;
return;
}
block++;
}
errcount = 0;
exit_return=1;
while (errcount < MAXERRORS) {
putchar(EOT);
if (getchar_t() == ACK)
{
exit_return=0;
break;
}
errcount++;
}
return;
}
/* receive a file from the remote */
recvfile(tfile)
char *tfile;
{
FILE *fp;
unsigned char hdr, blk, cblk, tmp, cksum;
unsigned char c1, c2, sum, block, sector[SECSIZE];
int i, stop = 0, mode, errcount, resync();
long true_end;
char ans[40];
if (!access(tfile, 00)) {
while (1) {
printf("File already exists \r\n");
return;
}
}
if (!(fp = fopen(tfile, "w"))) {
fprintf(stderr, "xmodem: Can't open '%s' for write\r\n", tfile);
return;
}
printf("File open - ready to receive\r\n");
rawmode();
errcount = 0;
block = 1;
sleep(10);
while (errcount < MAXERRORS) {
if (errcount < (MAXERRORS / 2)) {
putchar(NAK); /* try checksum mode first */
mode = 0;
}
else {
putchar('C'); /* then crc */
mode = 1;
}
if ((hdr = getchar_t()) == SOH) {
ungetc(SOH, stdin);
break;
}
errcount++;
}
if (errcount == MAXERRORS) {
sleep(3);
fprintf(stderr, "\r\nxmodem: Timed out on acknowledge\r\n");
return;
}
errcount = 0;
while (errcount < MAXERRORS) {
hdr = getchar_t();
if (hdr == CAN) {
sleep(3);
fprintf(stderr, "\r\nxmodem: Abort request received\r\n");
return;
}
if (hdr == EOT) /* done! */
break;
if (hdr != SOH) { /* read in junk for 6 seconds */
synchron = 0; /* to re-synchronized block */
signal(SIGALRM, resync);
alarm(6);
while(synchron == 0)
hdr = getchar();
goto nak;
}
blk = getchar_t();
cblk = getchar_t();
crc1 = 0;
crc2 = 0;
sum = 0;
for (i=0; i < SECSIZE; i++) {
sector[i] = getchar_t();
if (mode)
update_crc(sector[i]);
else
sum += sector[i];
}
if (mode) {
c1 = getchar_t();
c2 = getchar_t();
}
else
cksum = getchar_t();
if (blk != block && blk != (block - 1))
goto nak;
tmp = ~blk;
if (cblk != tmp)
goto nak;
if (mode) {
update_crc(0);
update_crc(0);
if (c1 != crc1 || c2 != crc2)
goto nak;
}
else {
if (cksum != sum)
goto nak;
}
if (block == blk) {
fflush(fp);
fwrite(sector, sizeof(sector[0]), SECSIZE, fp);
}
block = blk + 1;
putchar(ACK); /* got it! */
errcount = 0;
continue;
nak: putchar(NAK); /* do it over */
errcount++;
}
if (errcount == MAXERRORS) {
error();
return;
}
putchar(ACK);
for (i = SECSIZE -1; i >= 0; i--) { /* find true EOF */
if (sector[i] != CPMEOF) {
stop = i;
break;
}
}
/*
* Some CPM systems don't pad the end of the file with ^Z's so the file may
* have junk at the end. A conservative approach had to be taken in order
* for Unix object code (where ^Z's may be valid data) to transfer properly.
*/
true_end = ftell(fp) - SECSIZE + stop +1;
fclose(fp);
truncate(tfile, true_end);
return;
}
/* give minimal usage message */
usage()
{
fprintf(stderr, "Usage: xmodem [ s | r ] filename\r\n");
fprintf(stderr, " options are 's' for send or 'r' for receive\r\n");
return;
}
/* exceeded the maximum number of retry's */
error()
{
putchar(CAN);
putchar(CAN);
putchar(CAN);
putchar(CAN);
sleep(3);
fprintf(stderr, "\r\nxmodem: Exceeded error limit...aborting\r\n");
return;
}
/* update the CRC bytes */
update_crc(c)
unsigned char c;
{
int i, temp;
unsigned char carry, c_crc1, c_crc2;
for (i=0; i < 8; i++) {
temp = c * 2;
c = temp; /* rotate left */
carry = ((temp > 255) ? 1 : 0);
temp = crc2 * 2;
crc2 = temp;
crc2 |= carry; /* rotate with carry */
c_crc2 = ((temp > 255) ? 1 : 0);
temp = crc1 * 2;
crc1 = temp;
crc1 |= c_crc2;
c_crc1 = ((temp > 255) ? 1 : 0);
if (c_crc1) {
crc2 ^= 0x21;
crc1 ^= 0x10;
}
}
return;
}
/* getchar with a 10 sec time out */
getchar_t()
{
int force_it();
unsigned char c;
signal(SIGALRM, force_it);
alarm(10); /* only have 10 sec... */
c = getchar();
alarm(0);
return(c);
}
/*
* This code (and the resync() below) is the most machine dependent part
* of the program. The action of the signal SIGALRM during a read system
* call is not well defined. Some systems return the stack to the point
* outside the system call, others inside the call itself. Have fun...
*/
force_it()
{
unsigned char c;
c = CPMEOF; /* arbitrary default char */
#ifdef SV
ungetc(c, stdin);
#endif
#ifdef BSD
ioctl(0, TIOCSTI, &c);
#endif
return;
}
/* truncate file to given length */
truncate(path, length)
char *path;
long length;
{
FILE *fp, *tempfp;
long i;
char c, string[80], *tempfile, *mktemp();
if (!(fp = fopen(path, "r"))) {
fprintf(stderr, "xmodem: Can't open '%s' for read\r\n", path);
return;
}
tempfile = mktemp("/tmp/trunXXXXXX");
if (!(tempfp = fopen(tempfile, "w"))) {
fprintf(stderr, "xmodem: Can't open temporary file\r\n");
return;
}
for (i=0; i < length; i++) {
c = fgetc(fp);
fputc(c, tempfp);
}
fclose(fp);
fclose(tempfp);
sprintf(string, "mv %s %s", tempfile, path);
system(string);
return;
}
/* put the stdin/stdout in the "raw" mode */
rawmode()
{
#ifdef SV
struct termio tbuf;
ioctl(0, TCGETA, &tbuf);
tbuf.c_cc[4] = 1; /* VMIN */
tbuf.c_cc[5] = 0; /* VTIME */
tbuf.c_iflag = 0;
tbuf.c_oflag = 0;
tbuf.c_lflag = 0;
tbuf.c_cflag &= ~CSIZE;
tbuf.c_cflag |= CS8;
tbuf.c_cflag &= ~PARENB;
ioctl(0, TCSETAF, &tbuf);
return;
#endif
#ifdef BSD
struct sgttyb sgbuf;
ioctl(0, TIOCGETP, &sgbuf);
sgbuf.sg_flags |= RAW;
sgbuf.sg_flags &= ~ECHO;
ioctl(0, TIOCSETP, &sgbuf);
return;
#endif
}
/* after 6 seconds of reading junk data... */
resync()
{
char c;
synchron = 1; /* set the flag */
c = SOH;
#ifdef SV
ungetc(c, stdin);
#endif
#ifdef BSD
ioctl(0, TIOCSTI, &c);
#endif
return;
}