home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume32 / xbbs / part04 / checksum.c < prev   
C/C++ Source or Header  |  1992-09-08  |  10KB  |  483 lines

  1. /*
  2.  * A version of Ward Christensen's file transfer protocol for
  3.  * Unix System V or 4.2 bsd.
  4.  *
  5.  *        Emmet P. Gray, ..!ihnp4!uiucuxc!fthood!egray, 16 Aug 85
  6.  *
  7.  * Modified by Sanford Zelkovitz   08/18/86
  8.  * Last modification date: 05/20/87
  9.  */
  10.  
  11. #define SV
  12. #undef  BSD
  13.  
  14. #include <stdio.h>
  15. #include <signal.h>
  16. #include <sys/types.h>
  17. #include <sys/stat.h>
  18. #ifdef SV
  19. #include <termio.h>
  20. #endif
  21. #ifdef BSD
  22. #include <sgtty.h>
  23. #endif
  24.  
  25. #define MAXERRORS 10            /* max number of times to retry */
  26. #define SECSIZE    128            /* CP/M sector, transmission block */
  27. #define CPMEOF    26            /* End Of File (for CP/M) */
  28. #define SOH    1            /* Start Of Header */
  29. #define EOT    4            /* End Of Transmission */
  30. #define ACK    6            /* ACKnowledge */
  31. #define NAK    21            /* Negative AcKnowledge */
  32. #define CAN    24            /* CANcel */
  33.  
  34. int synchron;
  35. int exit_return;
  36. unsigned char crc1, crc2;
  37. #ifdef SV
  38. struct termio ttyhold;
  39. #endif
  40. #ifdef BSD
  41. struct sgttyb ttyhold;
  42. #endif
  43.  
  44. main(argc, argv)
  45. int argc;
  46. char *argv[];
  47. {
  48.     int msgstat;
  49.     char *tty, *ttyname();
  50.     struct stat stbuf;
  51.     exit_return=0;
  52.     if (argc != 3) {
  53.         usage();
  54.         exit(1);
  55.     }
  56.     tty = ttyname(1);
  57.     stat(tty, &stbuf); 
  58.     msgstat = (stbuf.st_mode & 0777);
  59.     chmod(tty, 0600);            /* mesg n */
  60. #ifdef SV
  61.     ioctl(0, TCGETA, &ttyhold);        /* get current settings */
  62. #endif
  63. #ifdef BSD
  64.     ioctl(0, TIOCGETP, &ttyhold);
  65. #endif
  66.     switch (*argv[1]) {
  67.         case 'r':
  68.             recvfile(argv[2]);
  69.             break;
  70.         case 's':
  71.             sendfile(argv[2]);
  72.             break;
  73.         default:
  74.             usage();
  75.     }
  76. #ifdef SV
  77.     ioctl(0, TCSETAF, &ttyhold);        /* restore settings */
  78. #endif
  79. #ifdef BSD
  80.     ioctl(0, TIOCSETP, &ttyhold);
  81. #endif
  82.     chmod(tty, msgstat);            /* restore mesg status */
  83.     exit(exit_return);
  84. }
  85.  
  86. /* send a file to the remote */
  87. sendfile(tfile)
  88. char *tfile;
  89. {
  90.     FILE *fp;
  91.     unsigned char chr, checksum, block, sector[SECSIZE];
  92.     int i, mode, nbytes, errcount, size, speed;
  93.     long min, sec;
  94.     static int baud[15] = {0, 50, 75, 110, 134, 150, 200,
  95.     300, 600, 1200, 1800, 2400, 4800, 9600, 19200};
  96.     struct stat sbuf;
  97.  
  98.     if (!(fp = fopen(tfile, "r"))) {
  99.         fprintf(stderr, "xmodem: Can't open '%s' for read\r\n", tfile);
  100.         exit_return=1;
  101.         return;
  102.     }
  103.     stat(tfile, &sbuf);
  104.     size = (sbuf.st_size / 128) + 1;
  105. #ifdef SV
  106.     speed = baud[ttyhold.c_cflag & 017];
  107. #endif
  108. #ifdef BSD
  109.     speed = baud[ttyhold.sg_ispeed];
  110. #endif
  111.     sec = size;
  112.     sec = sec * 128L * 11L / speed;
  113.     min = sec / 60L;
  114.     sec = sec - min * 60L;
  115.     printf("File open: %d records\r\n", size);
  116.     printf("Send time: %ld min, %ld sec at %d baud\r\n", min, sec, speed);
  117.     printf("To cancel: use CTRL-X numerous times\r\n");
  118.     printf("Waiting ready signal\r\n");
  119.  
  120.     rawmode();
  121.     errcount = 0;
  122.     mode = 0;
  123.     block = 1;
  124.     while (errcount < MAXERRORS) {
  125.         chr = getchar_t();
  126.         if (chr == NAK)            /* checksum mode */
  127.             break;
  128.         if (chr == 'C') {        /* CRC mode */
  129.             mode = 1;
  130.             break;
  131.         }
  132.         errcount++;
  133.     }
  134.     if (errcount == MAXERRORS) {
  135.         sleep(3);
  136.         fprintf(stderr, "xmodem: Timed out on acknowledge\r\n");
  137.         exit_return=1;
  138.         return;
  139.     }
  140.     while (nbytes = fread(sector, sizeof(sector[0]), SECSIZE, fp)) {
  141.         if (nbytes < SECSIZE) {        /* fill short sector */
  142.             for (i=nbytes; i < SECSIZE; i++)
  143.                 sector[i] = CPMEOF;
  144.         }
  145.         errcount = 0;
  146.         while (errcount < MAXERRORS) {
  147.             putchar(SOH);        /* the header */
  148.             putchar(block);        /* the block number */
  149.             chr = ~block;
  150.             putchar(chr);        /* it's complement */
  151.             checksum = 0;
  152.             crc1 = 0;
  153.             crc2 = 0;
  154.             for (i=0; i < SECSIZE; i++) {
  155.                 putchar(sector[i]);
  156.                 if (mode)
  157.                     update_crc(sector[i]);
  158.                 else
  159.                     checksum += sector[i];
  160.             }
  161.             if (mode) {
  162.                 update_crc(0);
  163.                 update_crc(0);
  164.                 putchar(crc1);
  165.                 putchar(crc2);
  166.             }
  167.             else
  168.                 putchar(checksum);
  169. rec_loop:
  170.             chr = getchar_t();
  171.             if (chr == CAN) {
  172.                 sleep(3);
  173.                 exit_return=1;
  174.                 fprintf(stderr,"\r\nxmodem: Abort request received\r\n");
  175.                 return;
  176.             }
  177.             if (chr == ACK)
  178.                 break;        /* got it! */
  179.             if (chr != NAK) goto rec_loop;  /* Noise on line? */
  180.             errcount++;
  181.         }
  182.         if (errcount == MAXERRORS) {
  183.             error();
  184.             exit_return=1;
  185.             return;
  186.         }
  187.         block++;
  188.     }
  189.     errcount = 0;
  190.     exit_return=1;
  191.     while (errcount < MAXERRORS) {
  192.         putchar(EOT);
  193.         if (getchar_t() == ACK)
  194.             {
  195.             exit_return=0;
  196.             break;
  197.             }
  198.         errcount++;
  199.     }
  200.     return;
  201. }
  202.  
  203. /* receive a file from the remote */
  204. recvfile(tfile)
  205. char *tfile;
  206. {
  207.     FILE *fp;
  208.     unsigned char hdr, blk, cblk, tmp, cksum;
  209.     unsigned char c1, c2, sum, block, sector[SECSIZE];
  210.     int i, stop = 0, mode, errcount, resync();
  211.     long true_end;
  212.     char ans[40];
  213.  
  214.     if (!access(tfile, 00)) {
  215.         while (1) {
  216.             printf("File already exists \r\n");
  217.                 return;
  218.         }
  219.     }
  220.  
  221.     if (!(fp = fopen(tfile, "w"))) {
  222.         fprintf(stderr, "xmodem: Can't open '%s' for write\r\n", tfile);
  223.         return;
  224.     }
  225.     printf("File open - ready to receive\r\n");
  226.     rawmode();
  227.     errcount = 0;
  228.     block = 1;
  229.     
  230.     sleep(10);
  231.     while (errcount < MAXERRORS) {
  232.         if (errcount < (MAXERRORS / 2)) {
  233.             putchar(NAK);        /* try checksum mode first */
  234.             mode = 0;
  235.         }
  236.         else {
  237.             putchar('C');        /* then crc */
  238.             mode = 1;
  239.         }
  240.         if ((hdr = getchar_t()) == SOH) {
  241.             ungetc(SOH, stdin);
  242.             break;
  243.         }
  244.         errcount++;
  245.     }
  246.     if (errcount == MAXERRORS) {
  247.         sleep(3);
  248.         fprintf(stderr, "\r\nxmodem: Timed out on acknowledge\r\n");
  249.         return;
  250.     }
  251.     errcount = 0;
  252.  
  253.     while (errcount < MAXERRORS) {
  254.         hdr = getchar_t();
  255.         if (hdr == CAN) {
  256.             sleep(3);
  257.             fprintf(stderr, "\r\nxmodem: Abort request received\r\n");
  258.             return;
  259.         }
  260.         if (hdr == EOT)            /* done! */
  261.             break;
  262.         if (hdr != SOH) {        /* read in junk for 6 seconds */
  263.             synchron = 0;        /*  to re-synchronized block */
  264.             signal(SIGALRM, resync);
  265.             alarm(6);
  266.             while(synchron == 0)
  267.                 hdr = getchar();
  268.             goto nak;
  269.         }
  270.         blk = getchar_t();
  271.         cblk = getchar_t();
  272.         crc1 = 0;
  273.         crc2 = 0;
  274.         sum = 0;
  275.         for (i=0; i < SECSIZE; i++) {
  276.             sector[i] = getchar_t();
  277.             if (mode)
  278.                 update_crc(sector[i]);
  279.             else
  280.                 sum += sector[i];
  281.         }
  282.         if (mode) {
  283.             c1 = getchar_t();
  284.             c2 = getchar_t();
  285.         }
  286.         else
  287.             cksum = getchar_t();
  288.         if (blk != block && blk != (block - 1))
  289.             goto nak;
  290.         tmp = ~blk;
  291.         if (cblk != tmp)
  292.             goto nak;
  293.         if (mode) {
  294.             update_crc(0);
  295.             update_crc(0);
  296.             if (c1 != crc1 || c2 != crc2)
  297.                 goto nak;
  298.         }
  299.         else {
  300.             if (cksum != sum)
  301.                 goto nak;
  302.         }
  303.         if (block == blk) {
  304.             fflush(fp);
  305.             fwrite(sector, sizeof(sector[0]), SECSIZE, fp);
  306.         }
  307.         block = blk + 1;
  308.         putchar(ACK);            /* got it! */
  309.         errcount = 0;
  310.         continue;
  311.  
  312.     nak:    putchar(NAK);            /* do it over */
  313.         errcount++;
  314.     }
  315.     if (errcount == MAXERRORS) {
  316.         error();
  317.         return;
  318.     }
  319.     putchar(ACK);
  320.     for (i = SECSIZE -1; i >= 0; i--) {    /* find true EOF */
  321.         if (sector[i] != CPMEOF) {
  322.             stop = i;
  323.             break;
  324.         }
  325.     }
  326. /*
  327.  * Some CPM systems don't pad the end of the file with ^Z's so the file may
  328.  * have junk at the end.  A conservative approach had to be taken in order
  329.  * for Unix object code (where ^Z's may be valid data) to transfer properly.
  330.  */
  331.     true_end = ftell(fp) - SECSIZE + stop +1;
  332.     fclose(fp);
  333.     truncate(tfile, true_end);
  334.     return;
  335. }
  336.  
  337. /* give minimal usage message */
  338. usage()
  339. {
  340.     fprintf(stderr, "Usage: xmodem [ s | r ] filename\r\n");
  341.     fprintf(stderr, "       options are 's' for send or 'r' for receive\r\n");
  342.     return;
  343. }
  344.  
  345. /* exceeded the maximum number of retry's */
  346. error()
  347. {
  348.     putchar(CAN);
  349.     putchar(CAN);
  350.     putchar(CAN);
  351.     putchar(CAN);
  352.     sleep(3);
  353.     fprintf(stderr, "\r\nxmodem: Exceeded error limit...aborting\r\n");
  354.     return;
  355. }
  356.  
  357. /* update the CRC bytes */
  358. update_crc(c)
  359. unsigned char c;
  360. {
  361.     int i, temp;
  362.     unsigned char carry, c_crc1, c_crc2;
  363.     for (i=0; i < 8; i++) {
  364.         temp = c * 2;
  365.         c = temp;            /* rotate left */
  366.         carry = ((temp > 255) ? 1 : 0);
  367.         temp = crc2 * 2;
  368.         crc2 = temp;
  369.         crc2 |= carry;            /* rotate with carry */
  370.         c_crc2 = ((temp > 255) ? 1 : 0);
  371.         temp = crc1 * 2;
  372.         crc1 = temp;
  373.         crc1 |= c_crc2;
  374.         c_crc1 = ((temp > 255) ? 1 : 0);
  375.         if (c_crc1) {
  376.             crc2 ^= 0x21;
  377.             crc1 ^= 0x10;
  378.         }
  379.     }
  380.     return;
  381. }
  382.  
  383. /* getchar with a 10 sec time out */
  384. getchar_t()
  385. {
  386.     int force_it();
  387.     unsigned char c;
  388.     signal(SIGALRM, force_it);
  389.     alarm(10);                /* only have 10 sec... */
  390.     c = getchar();
  391.     alarm(0);
  392.     return(c);
  393. }
  394.  
  395. /*
  396.  * This code (and the resync() below) is the most machine dependent part
  397.  * of the program.  The action of the signal SIGALRM during a read system
  398.  * call is not well defined.  Some systems return the stack to the point
  399.  * outside the system call, others inside the call itself.  Have fun...
  400.  */
  401. force_it()
  402. {
  403.     unsigned char c;
  404.     c = CPMEOF;                /* arbitrary default char */
  405. #ifdef SV
  406.     ungetc(c, stdin);
  407. #endif
  408. #ifdef BSD
  409.     ioctl(0, TIOCSTI, &c);
  410. #endif
  411.     return;
  412. }
  413.  
  414. /* truncate file to given length */
  415. truncate(path, length)
  416. char *path;
  417. long length;
  418. {
  419.     FILE *fp, *tempfp;
  420.     long i;
  421.     char c, string[80], *tempfile, *mktemp();
  422.     if (!(fp = fopen(path, "r"))) {
  423.         fprintf(stderr, "xmodem: Can't open '%s' for read\r\n", path);
  424.         return;
  425.     }
  426.     tempfile = mktemp("/tmp/trunXXXXXX");
  427.     if (!(tempfp = fopen(tempfile, "w"))) {
  428.         fprintf(stderr, "xmodem: Can't open temporary file\r\n");
  429.         return;
  430.     }
  431.     for (i=0; i < length; i++) {
  432.         c = fgetc(fp);
  433.         fputc(c, tempfp);
  434.     }
  435.     fclose(fp);
  436.     fclose(tempfp);
  437.     sprintf(string, "mv %s %s", tempfile, path);
  438.     system(string);
  439.     return;
  440. }
  441.  
  442. /* put the stdin/stdout in the "raw" mode */
  443. rawmode()
  444. {
  445. #ifdef SV
  446.     struct termio tbuf;
  447.     ioctl(0, TCGETA, &tbuf);
  448.     tbuf.c_cc[4] = 1;            /* VMIN */
  449.     tbuf.c_cc[5] = 0;            /* VTIME */
  450.     tbuf.c_iflag = 0;
  451.     tbuf.c_oflag = 0;
  452.     tbuf.c_lflag = 0;
  453.     tbuf.c_cflag &= ~CSIZE;
  454.     tbuf.c_cflag |= CS8;
  455.     tbuf.c_cflag &= ~PARENB;
  456.     ioctl(0, TCSETAF, &tbuf);
  457.     return;
  458. #endif
  459. #ifdef BSD
  460.     struct sgttyb sgbuf;
  461.     ioctl(0, TIOCGETP, &sgbuf);
  462.     sgbuf.sg_flags |= RAW;
  463.     sgbuf.sg_flags &= ~ECHO;
  464.     ioctl(0, TIOCSETP, &sgbuf);
  465.     return;
  466. #endif
  467. }
  468.  
  469. /*  after 6 seconds of reading junk data... */
  470. resync()
  471. {
  472.     char c;
  473.     synchron = 1;                /* set the flag */
  474.     c = SOH;
  475. #ifdef SV
  476.     ungetc(c, stdin);
  477. #endif
  478. #ifdef BSD
  479.     ioctl(0, TIOCSTI, &c);
  480. #endif
  481.     return;
  482. }
  483.