home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Utilities / uupc 3.1 / (uupc π) / dcpgpkt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-01  |  31.9 KB  |  1,147 lines  |  [TEXT/KAHL]

  1. /*
  2.    For best results in visual layout while viewing this file, set
  3.    tab stops to every 4 columns.
  4. */
  5.  
  6. /*
  7.    dcpgpkt.c
  8.  
  9.    Revised edition of dcp
  10.  
  11.    Stuart Lynne May/87
  12.  
  13.    Copyright (c) Richard H. Lamb 1985, 1986, 1987
  14.    Changes Copyright (c) Stuart Lynne 1987
  15.  
  16.             Portions Copyright © David Platt, 1992, 1991.  All Rights Reserved
  17.             Worldwide.
  18.  
  19.    Maintenance notes:
  20.  
  21.    25Aug87 - Allow for up to 7 windows - Jal
  22.    01Nov87 - those strncpy's should really be memcpy's! - Jal
  23.    11Sep89 - Raise TimeOut to 15 - ahd
  24.    30Apr90 - Add Jordon Brown's fix for short packet retries.
  25.              Reduce retry limit to 20                             ahd
  26.    22Jul90 - Change error retry limit from per host to per
  27.              packet.                                              ahd
  28.    22Jul90 - Add error message for number of retries exceeded     ahd
  29.    08Sep90 - Drop memmove to memcpy change supplied by Jordan
  30.              Brown, MS 6.0 and Turbo C++ agree memmove insures
  31.              no overlap
  32. */
  33.  
  34. /* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
  35.  
  36. /* 7-window "g" ptotocol */
  37.  
  38. /*
  39.    Thanks goes to John Gilmore for sending me a copy of Greg Chesson's
  40.    UUCP protocol description -- Obviously invaluable.
  41.    Thanks also go to Andrew Tannenbaum for the section on Siding window
  42.    protocols with a program example in his "Computer Networks" book.
  43. */
  44.  
  45. #include <stdio.h>
  46. #include <string.h>
  47. #include <time.h>
  48.  
  49. #include "dcp.h"
  50. #include "sio.h"
  51.  
  52. #define PKTSIZE   MAXPACK
  53.  
  54. #define HDRSIZE   6
  55. #define MAXTRY 4
  56.  
  57. /* g-packet type definitions */
  58.  
  59. #define DATA   0
  60. #define CLOSE  1
  61. #define NAK    2
  62. #define SRJ    3
  63. #define ACK    4
  64. #define  INITC 5
  65. #define INITB  6
  66. #define INITA  7
  67.  
  68. #define POK    -1
  69.  
  70. #define MAXWINDOW 7
  71. #define DFLWINDOW 3
  72. #define NBUF   8  /* always SAME as MAXSEQ ? */
  73. #define MAXSEQ 8
  74.  
  75. #define between(a,b,c) ((a<=b && b<c) || (c<a && a<=b) || (b<c && c<a))
  76.  
  77. #define nextpkt(x)    ((x + 1) % MAXSEQ)
  78.  
  79. #include "dcpgpkt.proto.h"
  80. static int gmachine(long int timeout);
  81. static void gspack(int type, int yyy, int xxx, int len, int xmit, char *data);
  82. static int grpack(int *yyy, int *xxx, int *len, char *data, int timeoutX);
  83. static unsigned int checksum(char *data, int len);
  84.  
  85. /* packet definitions */
  86.  
  87. static int rwl, swl, swu, rwu, nbuffers, irec, timeout;
  88. static int nerr;
  89. static int GOT_SYNC, GOT_HDR, skipped_to_sync;
  90. static int fseq[NBUF], outlen[NBUF], inlen[NBUF], arrived[NBUF], xmitlen[NBUF];
  91. static int nwindows;
  92. static char *outbuf[NBUF];
  93. static char *inbuf[NBUF];
  94. static long ftimer[NBUF], acktmr, naktmr;
  95. static long nakholdoff;
  96. static char rescan[PKTSIZE+HDRSIZE+10];
  97. static int rescanct, rescanoffset;
  98. static int shifts;
  99. static boolean smart_packets;
  100.  
  101. static int  gmachine(long int timeout);
  102. static void gspack(int  type,int  yyy,int  xxx,int  len,int xmit,char  *data);
  103. static int  grpack(int  *yyy,
  104.                    int  *xxx,
  105.                    int  *len,
  106.                    char *data,
  107.                    const int timeout);
  108.  
  109. static unsigned int checksum(char *data, int len);
  110.  
  111. /****************** SUB SUB SUB PACKET HANDLER ************/
  112.  
  113. /*
  114.    g o p e n p k
  115. */
  116.  
  117. int gopenpk(int master)
  118. {
  119.    int i, xxx, yyy, len, force_big;
  120.    int maxoffer;
  121.    char tmp[PKTSIZE+1];
  122.    int sync_timeout;
  123.  
  124.    pktsize = DFLPACK;   /* change it during parse & INIT */
  125.    msgtime = MSGTIME;   /* not sure I need this for "g" proto */
  126.  
  127.    /* initialize proto parameters */
  128.    swl = nerr = nbuffers = 0;
  129.    if (!sync_timeout)
  130.       sync_timeout = PacketTimeout + 1;
  131.    swl = swu = 1;
  132.    rwl = 0;
  133.    rescanct = 0;
  134.    rescanoffset = 0;
  135.    nwindows = DFLWINDOW;
  136.    smart_packets = FALSE;
  137.    force_big = FALSE;
  138.    (*currentConnection->SetParity)(data8, noParity);
  139.    if (strlen(proto) > 1) {
  140.     i = proto[1] - '0';
  141.     if (i > 0 && i <= MAXWINDOW) {
  142.         nwindows = i;
  143.     }
  144.     if (proto[2] == '/' || proto[2] == ':' || proto[2] == '!') {
  145.         sscanf(proto+3, "%d", &i);
  146.         xxx = 0;
  147.         yyy = 32;
  148.         while (yyy <= MAXPACK && yyy != i) {
  149.             xxx ++;
  150.             yyy *= 2;
  151.         }
  152.         if (yyy <= MAXPACK && yyy == i) {
  153.             pktsize = i;
  154.         }
  155.         if (proto[2] == ':') {
  156.             smart_packets = TRUE;
  157.         } else if (proto[2] == '!') {
  158.             smart_packets = TRUE;
  159.             force_big = TRUE;
  160.         }
  161.     }
  162.    }
  163.    maxoffer = pktsize;
  164.    rwu = nwindows - 1; /* dcp */
  165.    for (i = 0; i < NBUF; i++) {
  166.       ftimer[i] = 0;
  167.       arrived[i] = FALSE;
  168.    }
  169.    GOT_SYNC = GOT_HDR = FALSE;
  170.    skipped_to_sync = 0;
  171.    printmsg(2, "Offer: window %d, packet size %d", nwindows, maxoffer);
  172.  
  173.    /* 3-way handshake */
  174.    timeout = 2; /* want some timeout capability here */
  175.    gspack(INITA, 0, 0, 0, 0, NULL);
  176. rsrt:
  177.    if (nerr >= MaxErr)
  178.    {
  179.       printmsg(0,
  180.          "gopenpk: Consecutive error limit of %d exceeded, %ld total errors",
  181.           MaxErr, nerr + remote_stats.errors);
  182.       return(FAILED);
  183.    }
  184.  
  185.    /* INIT sequence. */
  186.  
  187.    switch (grpack(&yyy, &xxx, &len, NULL, PacketTimeout )) {
  188.    case INITA:
  189.       printmsg(5, "**got INITA");
  190.       if (yyy < nwindows) {
  191.           nwindows = yyy;
  192.       }
  193. #ifdef NOTDEF
  194.       nwindows = yyy;
  195.       if (nwindows > MAXWINDOW)
  196.          nwindows = MAXWINDOW;
  197. #endif
  198.       rwu = nwindows - 1;
  199.          printmsg(2, "Peer says: max window %d", yyy);
  200.       gspack(INITB, 0, 0, 0, 0, NULL);  /* data segment (packet) size */
  201.       goto rsrt;
  202.    case INITB:
  203.       printmsg(5, "**got INITB");
  204.       i = 8 * (2 << (yyy+1));
  205.          printmsg(2, "Peer says: packet size %d", i);
  206.       if (i < pktsize && ! force_big)
  207.          pktsize = i;
  208.       gspack(INITC, 0, 0, 0, 0, NULL);
  209.       goto rsrt;
  210.    case INITC:
  211.       printmsg(5, "**got INITC");
  212.       if (yyy < nwindows)
  213.       {
  214.               printmsg(2, "Peer says: max window %d", yyy);
  215.          nwindows = yyy;
  216.          rwu = nwindows - 1;
  217.       }
  218.       break;
  219.    default:
  220.       nerr++;
  221.       printmsg(5, "**got SCREW UP");
  222.       gspack(INITA, 0, 0, 0, 0, NULL);
  223.       goto rsrt;
  224.    }
  225.  
  226. /*--------------------------------------------------------------------*/
  227. /*                    Allocate the needed buffers                     */
  228. /*--------------------------------------------------------------------*/
  229.  
  230.    i = 0;
  231.    while( i < NBUF)
  232.    {
  233.  
  234.       inbuf[i] = NewPtr( maxoffer );
  235.       outbuf[i] = NewPtr( maxoffer );
  236.       if (inbuf[i] == NULL || outbuf[i] == NULL) {
  237.           printmsg(0, "*** Could not allocate packet buffers!");
  238.           return(FAILED);
  239.       }
  240.  
  241.       i ++;
  242.  
  243.    } /* while */
  244.    
  245.    nerr = 0;
  246.    nakholdoff = 0;
  247.    printmsg(1, "Channel open, %c%d/%d, smart packets %sabled", proto[0], nwindows, pktsize,
  248.             smart_packets ? "en" : "dis");
  249.    return(OK); /* channel open */
  250.  
  251. } /*gopenpk*/
  252.  
  253.  
  254. /*
  255.    g c l o s e p k
  256. */
  257.  
  258. int gclosepk(void)
  259. {
  260.    int i;
  261.    char tmp[PKTSIZE+1];
  262.  
  263.    timeout = 1;
  264.    for (i = 0; i < MAXTRY; i++) {
  265.       gspack(CLOSE, 0, 0, 0, 0, NULL);
  266.       if (gmachine(PacketTimeout) == CLOSE)
  267.          break;
  268.    }
  269.  
  270.    printmsg(0, "%ld packets transferred, %ld errors.", remote_stats.packets,
  271.          nerr + remote_stats.errors);
  272.  
  273. /*--------------------------------------------------------------------*/
  274. /*                        Release our buffers                         */
  275. /*--------------------------------------------------------------------*/
  276.  
  277.    i = 0;
  278.  
  279.    while( i < NBUF )
  280.    {
  281.       DisposPtr(inbuf[i] );
  282.       DisposPtr( outbuf[i] );
  283.       inbuf[i] = outbuf[i] = NULL;
  284.       i++;
  285.    } /* while( i < NBUF ) */
  286.  
  287.    return(0);
  288.  
  289. } /*gclosepk*/
  290.  
  291.  
  292. /*
  293.    g g e t p k t
  294.  
  295.    Gets no more than a packet's worth of data from
  296.    the "packet I/O state machine".  May have to
  297.    periodically run the packet machine to get some packets.
  298.  
  299.    on input:   don't care
  300.    on return:  data+\0 and length in len.
  301.  
  302.    ret(0)   if all's well
  303.    ret(-1) if problems (failed)
  304. */
  305.  
  306. int ggetpkt(char *data, int *len)
  307. {
  308.    int   i;
  309.    int   retry = MaxErr;
  310.    time_t start;
  311.  
  312.    irec = 1;
  313.  
  314. /*--------------------------------------------------------------------*/
  315. /*                Loop to wait for the desired packet                 */
  316. /*--------------------------------------------------------------------*/
  317.  
  318.    time( &start );
  319.    while (!arrived[rwl] && retry)
  320.    {
  321.       if (gmachine(PacketTimeout) != POK)
  322.          return(-1);
  323.  
  324.       if (!arrived[rwl] )
  325.       {
  326.          time_t now;
  327.          if (time( &now ) > (start + PacketTimeout) )
  328.          {
  329.             printmsg(5,"ggetpkt: Timeout %d waiting for inbound packet %d",
  330.                      MaxErr - --retry, remote_stats.packets + 1);
  331. /*            timeouts++; */
  332.             start = now;
  333.          } /* if (time( now ) > (start + E_PacketTimeout) ) */
  334.       } /* if (!arrived[rwl] ) */
  335.    } /* while (!arrived[rwl] && i) */
  336.  
  337.    if (!arrived[rwl])
  338.    {
  339.       printmsg(0,"ggetpkt: Remote host failed to respond after %ld seconds",
  340.                (long) PacketTimeout * MaxErr);
  341. /* removed per Bo Holst-Christensen
  342.      gclosepk();
  343. */
  344.       return -1;
  345.    }
  346.  
  347. /*--------------------------------------------------------------------*/
  348. /*                           Got a packet!                            */
  349. /*--------------------------------------------------------------------*/
  350.  
  351.    i = rwl; /*<-- mod(,rwindow) for larger than 8 seq no.s */
  352.    *len = inlen[i];
  353.    memcpy(data, inbuf[i], *len);
  354.    nerr = 0; /* reset error counter */
  355.  
  356.    arrived[i] = FALSE;
  357.    rwu = nextpkt(rwu)        ;  /* bump receive window */
  358.  
  359.    remote_stats.packets++;
  360.    remote_stats.breceived += *len;
  361.  
  362.    return(0);
  363.  
  364. } /*ggetpkt*/
  365.  
  366.  
  367.  
  368.  
  369. /*
  370.    g s e n d p k t
  371.  
  372.    Put at most a packet's worth of data in the packet state
  373.    machine for transmission.
  374.    May have to run the packet machine a few times to get
  375.    an available output slot.
  376.  
  377.    on input: data=*data; len=length of data in data.
  378.  
  379.    return:
  380.     0 if all's well
  381.    -1 if problems (failed)
  382. */
  383.  
  384. int gsendpkt(char *data, int len)
  385. {
  386.    int i1;
  387.    int delta;
  388. #ifdef _DEBUG
  389.    int savedebug = debuglevel;
  390. #endif
  391.  
  392.    irec = 0;
  393.    /* WAIT FOR INPUT i.e. if weve sent SWINDOW pkts and none have been
  394.       acked, wait for acks */
  395.    while (nbuffers >= nwindows)
  396.       if (gmachine(0) != POK)    /* Spin with no timeout             */
  397.          return(-1);
  398.  
  399.    i1 = swu;   /* <--If we ever have more than 8 seq no.s, must mod() here */
  400.  
  401. /*--------------------------------------------------------------------*/
  402. /*               Place packet in table and mark unacked               */
  403. /*--------------------------------------------------------------------*/
  404.  
  405.    memcpy(outbuf[i1], data, len);
  406.  
  407. /*--------------------------------------------------------------------*/
  408. /*                       Handle short packets.                        */
  409. /*--------------------------------------------------------------------*/
  410.  
  411.    xmitlen[i1] = pktsize;
  412.    if (smart_packets)
  413.       while ( ((len * 2) < xmitlen[i1]) && (xmitlen[i1] > 32) )
  414.          xmitlen[i1] /= 2;
  415.  
  416.    delta = xmitlen[i1] - len;
  417.    if (delta > 127)
  418.    {
  419.       memmove(outbuf[i1] + 2, outbuf[i1], len);
  420.       memset(outbuf[i1]+len+2, 0, delta - 2);
  421.                               /* Pad with nulls.  Ugh.               */
  422.       outbuf[i1][0] = (unsigned char) ((delta & 0x7f) | 0x80);
  423.       outbuf[i1][1] = (unsigned char) (delta >> 7);
  424.    } /* if (delta > 127) */
  425.    else if (delta > 0 )
  426.    {
  427.       memmove(outbuf[i1] + 1, outbuf[i1], len);
  428.       outbuf[i1][0] = (unsigned char) delta;
  429.       memset(outbuf[i1]+len+1, 0, delta - 1);
  430.                               /* Pad with nulls.  Ugh.               */
  431.    } /* else if (delta > 0 )  */
  432.  
  433. /*--------------------------------------------------------------------*/
  434. /*                            Mark packet                             */
  435. /*--------------------------------------------------------------------*/
  436.  
  437.    outlen[i1] = len;
  438.    ftimer[i1] = time((long int) NULL);
  439.    swu = nextpkt(swu);  /* bump send window */
  440.    nbuffers++;
  441.  
  442.    remote_stats.packets++;
  443.    remote_stats.bsent += len;
  444.  
  445. /*--------------------------------------------------------------------*/
  446. /*                              send it                               */
  447. /*--------------------------------------------------------------------*/
  448.  
  449.    gspack(DATA, rwl, i1, outlen[i1], xmitlen[i1], outbuf[i1]);
  450.  
  451. #ifdef _DEBUG
  452.    debuglevel = savedebug;
  453. #endif
  454.  
  455.    return(0);
  456.  
  457. } /*gsendpkt*/
  458.  
  459.  
  460. int gfilepkt(void)
  461. {
  462.     return 0; /* begin data phase */
  463. }
  464.  
  465. int geofpkt(void)
  466. {
  467.     int len;
  468.     char spacket[MAXPACK];
  469.     if(gsendpkt(spacket, 0))
  470.         return('N');
  471.     return 'Y';
  472. }
  473.  
  474. int gsendresp(int state)
  475. {
  476.     return OK;
  477. }
  478.  
  479. /**********  Packet Machine  ********** RH Lamb 3/87 */
  480.  
  481. /*
  482.    g m a c h i n e
  483.  
  484.    Ideally we would like to fork this process off in an infinite loop and
  485.    send and receive packets through "inbuf" and "outbuf". Can't do this in
  486.    MS-DOS so we setup "getpkt" and "sendpkt" to call this routine often and
  487.    return only when the input buffer is empty thus "blocking" the packet-
  488.    machine task.
  489. */
  490.  
  491. static int gmachine(long int timeout)
  492. {
  493.    boolean done   = FALSE;    /* True = drop out of machine loop  */
  494.    boolean close  = FALSE;    /* True = terminate connection upon
  495.                                         exit                      */
  496.    char rdata[PKTSIZE+1];
  497.  
  498.    while ( !done )
  499.    {
  500.       boolean resend = FALSE;    /* True = resend data packets       */
  501.       boolean donak  = FALSE;    /* True = NAK the other system      */
  502.  
  503.       int packet, rack, rseq, rlen, i1;
  504.       time_t expired;
  505.  
  506.       printmsg(10, "* send %d < W < %d, receive %d < W < %d, error %d",
  507.          swl, swu, rwl, rwu, nerr);
  508.  
  509. /*--------------------------------------------------------------------*/
  510. /*    Waiting for ACKs for swl to swu-1.  Next pkt to send=swu        */
  511. /*    rwl=expected pkt                                                */
  512. /*--------------------------------------------------------------------*/
  513.  
  514.       printmsg(7, "Bytes transfered %ld errors %d",
  515.        (long) (remote_stats.packets * PKTSIZE) , nerr);
  516.  
  517. /*--------------------------------------------------------------------*/
  518. /*             Attempt to retrieve a packet and handle it             */
  519. /*--------------------------------------------------------------------*/
  520.  
  521.       packet = grpack(&rack, &rseq, &rlen, rdata, timeout);
  522.       switch (packet) {
  523.  
  524.          case CLOSE:
  525.             printmsg(5, "**got CLOSE");
  526.             close = done = TRUE;
  527.             break;
  528.  
  529.          case EMPTY:
  530.             printmsg(6, "**got EMPTY");
  531.             expired = time(NULL) - PacketTimeout;
  532.             for (rack = swl; between(swl, rack, swu); rack = nextpkt(rack))
  533.             {
  534.                printmsg(6, "---> seq, elapst %d %ld", rack,
  535.                     ftimer[rack] - expired);
  536.                if (ftimer[rack] && (ftimer[rack] <= expired))
  537.                {
  538.                    printmsg(5, "*** timeout %d", rack);
  539.                          /* Since "g" is "go-back-N", when we time out we
  540.                           must send the last N pkts in order.  The generalized
  541.                           sliding window scheme relaxes this reqirment. */
  542.                    nerr++;
  543.                    resend = TRUE;
  544.                    break;
  545.                } /* if */
  546.             } /* for */
  547.             done = TRUE;
  548.             break;
  549.  
  550.          case NAK:
  551.          case ACK:
  552.             if (packet == NAK)
  553.             {
  554.                nerr++;
  555.                printmsg(5, "**got NAK %d", rack);
  556.                resend = TRUE;
  557.             }
  558.             else
  559.                printmsg(5, "**got ACK %d", rack);
  560.  
  561.             while(between(swl, rack, swu))
  562.             {                             /* S<-- -->(S+W-1)%8 */
  563.                printmsg(5, "*** ACK %d", swl);
  564.                ftimer[swl] = 0;
  565.                nbuffers--;
  566.                done = TRUE;            /* Get more data for input */
  567.                swl = nextpkt(swl);
  568.             } /* while */
  569.             if (!done && (packet == ACK)) /* Find packet?         */
  570.             {
  571.                printmsg(2,"gmachine: Received ACK for bad packet %d, window is %d-%d)", rack, swl, swu);
  572.                nerr++;                 /* Count an error and proceed */
  573.             }
  574.             break;
  575.  
  576.          case DATA:
  577.             printmsg(5, "**got DATA %d %d", rack, rseq);
  578.             i1 = nextpkt(rwl);   /* (R+1)%8 <-- -->(R+W)%8 */
  579.             if (i1 == rseq) {
  580.                nakholdoff--;
  581.                arrived[i1] = TRUE;
  582.                inlen[i1] = rlen;
  583.                memcpy(inbuf[i1], rdata, rlen);
  584.                rwl = i1;
  585.                printmsg(5, "*** ACK d %d", rwl);
  586.                gspack(ACK, rwl, 0, 0, pktsize, rdata);
  587.                done = TRUE;   /* return to caller when finished */
  588.                               /* in a mtask system, unneccesary */
  589.                while(between(swl, rack, swu))
  590.                 {                             /* S<-- -->(S+W-1)%8 */
  591.                    printmsg(5, "*** implicit ACK %d", swl);
  592.                    ftimer[swl] = 0;
  593.                    nbuffers--;
  594.                    swl = nextpkt(swl);
  595.                 } /* while */
  596.             } else {
  597.                nerr++;
  598.                printmsg(5, "*** unexpect %d ne %d - %d", rseq, rwl, rwu);
  599.                donak = TRUE;
  600.             }
  601.             break;
  602.  
  603.          case ERROR:
  604.             printmsg(5, "*** got BAD CHK");
  605.             donak = TRUE;
  606.             nakholdoff = 0; /* always NAK these to prevent stalling */
  607.             break;
  608.  
  609.          default:
  610.             printmsg(5, "*** got SCREW UP");
  611.             break;
  612.  
  613.       } /* switch */
  614.  
  615. /*--------------------------------------------------------------------*/
  616. /*      If we received an NAK or timed out, resend data packets       */
  617. /*--------------------------------------------------------------------*/
  618.  
  619.       if (resend)
  620.       for (rack = swl; between(swl, rack, swu); rack = nextpkt(rack))
  621.       {                          /* resend rack->(swu-1)             */
  622.          gspack(DATA, rwl, rack, outlen[rack], pktsize, outbuf[rack]);
  623.          printmsg(5, "*** resent %d", rack);
  624.          ftimer[rack] = time((long) NULL);
  625.       } /* for */
  626.  
  627. /*--------------------------------------------------------------------*/
  628. /*  If we have an error and have not recently sent a NAK, do so now.  */
  629. /*  We then reset our counter so we receive at least a window full of */
  630. /*                 packets before sending another NAK                 */
  631. /*--------------------------------------------------------------------*/
  632.  
  633.       if ( donak )
  634.       {
  635.          nerr++;
  636.          if ( nakholdoff <= 0 )
  637.          {
  638.             printmsg(5, "*** NAK d %d", rwl);
  639.             gspack(NAK, rwl, 0, 0, pktsize, rdata);
  640.             nakholdoff = nwindows + 1;
  641.          } /* if ( nakholdoff < 1 ) */
  642.       } /* if ( donak ) */
  643.  
  644. /*--------------------------------------------------------------------*/
  645. /*    If we have an excessive number of errors, drop out of the       */
  646. /*    loop                                                            */
  647. /*--------------------------------------------------------------------*/
  648.  
  649.       if (nerr >= MaxErr)
  650.       {
  651.          printmsg(0,
  652.             "gmachine: Consecutive error limit of %d exceeded, %ld total errors",
  653.             MaxErr, nerr + remote_stats.errors);
  654.          remote_stats.errors += nerr;
  655.          nerr = 0;
  656.          done = close = TRUE;
  657.       }
  658.    } /* while */
  659.  
  660. /*--------------------------------------------------------------------*/
  661. /*    Return to caller, gracefully terminating packet machine if      */
  662. /*    requested                                                       */
  663. /*--------------------------------------------------------------------*/
  664.  
  665.    if ( close )
  666.    {
  667.       gspack(CLOSE, 0, 0, 0, pktsize, rdata);
  668.       return CLOSE;
  669.    }
  670.    else
  671.       return POK;
  672.  
  673. } /*gmachine*/
  674.  
  675.  
  676. /*************** FRAMING *****************************/
  677.  
  678. /*
  679.    g s p a c k
  680.  
  681.    Send a packet
  682.  
  683.    type=type yyy=pkrec xxx=timesent len=length<=xmit xmit=pktsize data=*data
  684.    ret(0) always
  685. */
  686.  
  687. static void gspack(int type, int yyy, int xxx, int len, int xmit, char *data)
  688. {
  689.    unsigned int check, i;
  690.    unsigned char header[HDRSIZE];
  691.  
  692. #ifdef   LINKTEST
  693.    /***** Link Testing Mods *****/
  694.    unsigned char  dpkerr[10];
  695.    /***** End Link Testing Mods *****/
  696. #endif   /* LINKTEST */
  697.  
  698. #ifdef   LINKTEST
  699.    /***** Link Testing Mods - create artificial errors *****/
  700.    printf("**n:normal,e:error,l:lost,p:partial,h:bad header,s:new seq--> ");
  701.    gets(dpkerr);
  702.    if (dpkerr[0] == 's')
  703.       sscanf(&dpkerr[1], "%d", &xxx);
  704.    /***** End Link Testing Mods *****/
  705. #endif   /* LINKTEST */
  706.  
  707.    if ( debuglevel > 4 )
  708.       printmsg(5, "send packet type %d, yyy=%d, xxx=%d, len=%d, buf = %d",
  709.                type, yyy, xxx, len, xmit);
  710.  
  711.    header[0] = '\020';
  712.    header[4] = (unsigned char) (type << 3);
  713.  
  714.    switch (type) {
  715.  
  716.       case CLOSE:
  717.          break;   /* stop protocol */
  718.  
  719.       case NAK:
  720.          header[4] += yyy;
  721.          break;   /* reject */
  722.  
  723.       case SRJ:
  724.          break;
  725.  
  726.       case ACK:
  727.          header[4] += yyy;
  728.          break;   /* ack */
  729.  
  730.       case INITA:
  731.       case INITC:
  732.          header[4] += nwindows;
  733.          break;
  734.  
  735.       case INITB:
  736.          i = 32;
  737.          while( i < pktsize )
  738.          {
  739.             header[4] ++;
  740.             i *= 2;
  741.          }
  742.          break;
  743.  
  744.       case DATA:
  745.          header[4] = (unsigned char) (0x80 + (xxx << 3) + yyy);
  746.          if (len < pktsize)   /* Short packet?                       */
  747.          {
  748.             header[4] |= 0x40;/* Count byte handled at higher level */
  749.             printmsg(7, "data=|%.*s|", len, data);
  750.          }
  751.          else
  752.             printmsg(7, "data=|%.*s|", len, data);
  753.          break;
  754.  
  755.       default:
  756.          printmsg(0,"gspack: Invalid packet type %i",type);
  757.          return;
  758.    } /* switch */
  759.  
  760. /*--------------------------------------------------------------------*/
  761. /*    Now we finish up the header.  For data packets, determine       */
  762. /*    the K number in header[1], which specifies the number of        */
  763. /*    actual data bytes transmitted as a power of 2; we also          */
  764. /*    compute a checksum on the data.                                 */
  765. /*--------------------------------------------------------------------*/
  766.  
  767.    if (type == DATA)
  768.    {
  769.       header[1] = 1;
  770.       i = 32;
  771.       while( i < xmit )
  772.       {
  773.          header[1] ++;
  774.          i *= 2;
  775.       }
  776.  
  777.       if ( i != xmit )        /* Did it come out exact power of 2?   */
  778.       {
  779.          printmsg(0,"Packet length error ... %i != %i for K = %i",
  780.                i, xmit, (int) header[1]);
  781.          return;             /* No --> Well, we blew THAT math      */
  782.       } /* if ( i != xmit ) */
  783.  
  784. /*--------------------------------------------------------------------*/
  785. /*                        Compute the checksum                        */
  786. /*--------------------------------------------------------------------*/
  787.  
  788.       check = checksum(data, xmit);
  789.       i = header[4]; /* got to do this on PC for ex-or high bits */
  790.       i &= 0xff;
  791.       check = (check ^ i) & 0xffff;
  792.       check = (0xaaaa - check) & 0xffff;
  793.    }
  794.    else {
  795.       header[1] = 9;          /* Control packet size K number (9)    */
  796.       check = (0xaaaa - header[4]) & 0xffff;
  797.                               /* Simple checksum for control         */
  798.    } /* else */
  799.  
  800.    header[2] = (unsigned char) (check & 0xff);
  801.    header[3] = (unsigned char) ((check >> 8) & 0xff);
  802.    header[5] = (unsigned char)
  803.             ((header[1] ^ header[2] ^ header[3] ^ header[4]) & 0xff) ;
  804.  
  805. #ifdef   LINKTEST
  806.    /***** More Link Testing Mods *****/
  807.    switch(dpkerr[0]) {
  808.    case 'e':
  809.       data[10] = - data[10];
  810.       break;
  811.    case 'h':
  812.       header[5] = - header[5];
  813.       break;
  814.    case 'l':
  815.       return;
  816.    case 'p':
  817.       swrite((char *) header, HDRSIZE);
  818.       if (header[1] != 9)
  819.          swrite(data, xmit - 3);
  820.       return;
  821.    default:
  822.       break;
  823.    }
  824.    /***** End Link Testing Mods *****/
  825. #endif   /* LINKTEST */
  826.  
  827.    swrite((char *) header, HDRSIZE);      /* header is 6-bytes long */
  828.    if (header[1] != 9)
  829.       swrite(data, xmit);
  830.  
  831. } /*gspack*/
  832.  
  833.  
  834.  
  835. /*
  836.    g r p a c k
  837.  
  838.    Read packet
  839.  
  840.    on return: yyy=pkrec xxx=pksent len=length<=PKTSIZE  data=*data
  841.  
  842.    ret(type)   ok
  843.    ret(EMPTY)  input buf empty, or bad header
  844.  
  845.    ret(EMPTY)  lost packet timeout
  846.    ret(ERROR)  checksum error
  847.  
  848.    NOTE (specifications for sread()):
  849.  
  850.    sread(buf, n, timeout)
  851.       while(TRUE) {
  852.          if (# of chars available >= n) (without dec internal counter)
  853.             read n chars into buf (decrement internal char counter)
  854.             break
  855.          else
  856.             if (time > timeout)
  857.                break
  858.       }
  859.       return(# of chars available)
  860.  
  861. */
  862.  
  863. static int grpack(int *yyy, int *xxx, int *len, char *data, int timeoutX)
  864. {
  865.    unsigned int type, check, checkchk, i, total;
  866.    boolean badHeader;
  867.    unsigned char c, c2;
  868.    int hdroffset, hdrbytes, scanct, scanoffset, dbytes, dgot, doffset;
  869.    unsigned char grpkt[PKTSIZE+HDRSIZE];
  870.    const int sync_timeout = PacketTimeout + 1;
  871.                               /* Time willing to wait for sync char  */
  872.    time_t start;
  873.    time_t elapsed;
  874.  
  875.    if (GOT_HDR)
  876.       goto get_data;
  877.  
  878. /*--------------------------------------------------------------------*/
  879. /*   Spin up to timeout waiting for a Control-P, our sync character   */
  880. /*--------------------------------------------------------------------*/
  881.  
  882.    start = time((time_t) NULL); /* Rememeber we started looking for
  883.                                  sync character                      */
  884.    elapsed = 0;               /* No time has passed since start      */
  885.    
  886.    if (rescanct > 0) {
  887.       printmsg(1, "grpack: rescanning %d bytes", rescanct);
  888.    }
  889.  
  890.    while (!GOT_SYNC && (elapsed < sync_timeout))
  891.    {
  892.       if (rescanct > 0) {
  893.          c = rescan[rescanoffset++];
  894.          rescanct--;
  895.       } else if (sread( (char *) &c , 1, sync_timeout) < 1)
  896.       {
  897.          nerr++;                 /* Otherwise, we never quit!        */
  898.          return EMPTY;
  899.       }
  900.       if ((c & 0x7f) == '\020') {
  901.          GOT_SYNC = TRUE;
  902.          if (skipped_to_sync > 0) {
  903.              printmsg(2, "Skipped %d bytes\n", skipped_to_sync);
  904.              skipped_to_sync = 0;
  905.          }
  906.       } else if ((c & 0x7f) != '\0') { /* Don't kvetch about nulls - known BSD bug */
  907.          time_t   now = time((time_t) NULL);  /* Get new time          */
  908.          elapsed = now - start;  /* Compute time used since start    */
  909.          if (skipped_to_sync == 0) {
  910.              printmsg(2, "grpack: %02x not a sync, skipping...", c);
  911.          }
  912.          skipped_to_sync ++;
  913.       } /* else */
  914.    } /* while */
  915.  
  916.    if ( !GOT_SYNC )
  917.       return EMPTY;
  918.  
  919. /*--------------------------------------------------------------------*/
  920. /*   We are in are in sync with the other host; now process the       */
  921. /*   header which should follow.                                      */
  922. /*--------------------------------------------------------------------*/
  923.    hdroffset = 1;
  924.    hdrbytes = HDRSIZE - 1;
  925.    scanct = rescanct;
  926.    scanoffset = rescanoffset;
  927.    while (rescanct > 0 && hdrbytes > 0) {
  928.       grpkt[hdroffset++] = rescan[rescanoffset++];
  929.       rescanct--;
  930.       hdrbytes--;
  931.    }
  932.    if (hdrbytes > 0 && sread( (char *) &grpkt[hdroffset], hdrbytes, PacketTimeout) < hdrbytes) {
  933.            printmsg(2, "grpack: timeout during packet header");
  934.            return(EMPTY);
  935.    }
  936.    GOT_SYNC = FALSE;
  937.    i = (unsigned)grpkt[1] ^ (unsigned)grpkt[2] ^
  938.        (unsigned)grpkt[3] ^ (unsigned)grpkt[4] ^
  939.        (unsigned)grpkt[5];
  940.  
  941.    i &= 0xff;
  942.    printmsg(10, "prpkt %02x %02x %02x %02x %02x .. %02x ",
  943.       grpkt[1], grpkt[2], grpkt[3], grpkt[4], grpkt[5], i);
  944.  
  945.  
  946.    if (i != 0) {
  947.         printmsg(0, "*** header cksum error ***");
  948.         badHeader = TRUE;
  949.    } else if (grpkt[1] != 9 /*ctl*/ && grpkt[1] > MAXPACKCODE) {  /* bad header */
  950.         printmsg(0, "*** bad header ***");
  951.         badHeader = TRUE;
  952.    } else {
  953.         badHeader = FALSE;
  954.    }
  955.    
  956.    if (badHeader) {
  957.       if (scanct > 0) {
  958.           rescanct = scanct;
  959.           rescanoffset = scanoffset;
  960.       } else {
  961.         rescanct = HDRSIZE - 1;
  962.         rescanoffset = 0;
  963.           memcpy(rescan, &grpkt[1], rescanct);
  964.       }
  965.       return(EMPTY); /* DECUS paper says not to NAK it */
  966.    }
  967.  
  968.    GOT_HDR = TRUE;
  969.    if (grpkt[1] == 9) { /* control packet */
  970.       if ( data != NULL )
  971.          *data = '\0';
  972.       *len = 0;
  973.       c = grpkt[4];
  974.       type = c >> 3;
  975.       *yyy = c & 0x07;
  976.       *xxx = 0;
  977.       check = 0;
  978.       checkchk = 0;
  979.       GOT_HDR = FALSE;
  980.    } else { /* data packet, packet size already verified */
  981. get_data:
  982.       if ( data == NULL )
  983.       {
  984.          printmsg(0,"grpack: Unexpected data packet!");
  985.          return(ERROR);
  986.       }
  987. /*--------------------------------------------------------------------*/
  988. /*             Compute the size of the data block desired             */
  989. /*--------------------------------------------------------------------*/
  990.  
  991.       total = 8 * (2 << grpkt[1]);
  992.       if (total > MAXPACK)    /* Within the defined limits?          */
  993.       {                       /* No --> Other system has bad header,
  994.                                  or the header got corrupted         */
  995.          printmsg(0,"grpack: Invalid packet size %d (%d)",
  996.             total, (int) grpkt[1]);
  997.          GOT_HDR = FALSE;
  998.          return(ERROR);
  999.       }
  1000.       if (rescanct > 0) {
  1001.          if (rescanct > total) {
  1002.              dbytes = total;
  1003.           } else {
  1004.              dbytes = rescanct;
  1005.           }
  1006.           memcpy(grpkt+HDRSIZE, rescan+rescanoffset, (size_t) dbytes);
  1007.           doffset = dbytes;
  1008.           rescanoffset += dbytes;
  1009.           rescanct -= dbytes;
  1010.           dbytes = total - dbytes;
  1011.       } else {
  1012.           dbytes = total;
  1013.           doffset = 0;
  1014.       }
  1015.       if (dbytes > 0) {
  1016.            dgot = sread((char *) grpkt+HDRSIZE+doffset, dbytes, PacketTimeout);
  1017.            if (dgot < dbytes) {
  1018.              rescanoffset = 0;
  1019.              rescanct = doffset + dgot;
  1020.              if (rescanct < 1) {
  1021.                  printmsg(1, "Timeout while reading packet, no data");
  1022.                  rescanct = 0;
  1023.              } else {
  1024.                  printmsg(1, "Timeout while reading packet, saving %d bytes", rescanct);
  1025.                  memcpy(rescan, grpkt+HDRSIZE, (size_t) rescanct);
  1026.             }
  1027.              return(EMPTY);
  1028.          }
  1029.       }
  1030.       GOT_HDR = FALSE;
  1031.       type = 0;
  1032.       c2 = grpkt[4];
  1033.       c = (unsigned char) (c2 & 0x3f);
  1034.       *xxx = c >> 3;
  1035.       *yyy = c & 0x07;
  1036.       i = grpkt[3];
  1037.       i = (i << 8) & 0xff00;
  1038.       check = grpkt[2];
  1039.       check = i | (check & 0xff);
  1040.       checkchk = checksum((char *) grpkt+HDRSIZE, total);
  1041.       i = grpkt[4] | 0x80;
  1042.       i &= 0xff;
  1043.       checkchk = 0xaaaa - (checkchk ^ i);
  1044.       checkchk &= 0xffff;
  1045.       if (checkchk != check) {
  1046.          printmsg(4, "*** packet checksum error ***");
  1047.          rescanoffset = 0;
  1048.          rescanct = total;
  1049.          memcpy(rescan, grpkt+HDRSIZE, (size_t) rescanct);
  1050.          return(ERROR);
  1051.       }
  1052. /*--------------------------------------------------------------------*/
  1053. /*    The checksum is correct, now determine the length of the        */
  1054. /*    data to return.                                                 */
  1055. /*--------------------------------------------------------------------*/
  1056.  
  1057.       *len = total;
  1058.  
  1059.       if (c2 & 0x40)
  1060.       {
  1061.          int ii;
  1062.          if ( grpkt[HDRSIZE] & 0x80 )
  1063.          {
  1064.             ii = (grpkt[HDRSIZE] & 0x7f) + ((grpkt[HDRSIZE+1] & 0xff) << 7);
  1065.             *len -= ii;
  1066.             memcpy(data, grpkt + HDRSIZE + 2, *len);
  1067.          }
  1068.          else {
  1069.             ii = (grpkt[HDRSIZE] & 0xff);
  1070.             *len -= ii;
  1071.             memcpy(data, grpkt + HDRSIZE + 1, *len);
  1072.          } /* else */
  1073.       }
  1074.       else
  1075.          memcpy(data, grpkt + HDRSIZE, *len);
  1076.       data[*len] = '\0';
  1077.    }
  1078.  
  1079.    printmsg(12, "receive packet type %d, yyy=%d, xxx=%d, len=%d",
  1080.       type, *yyy, *xxx, *len);
  1081.    printmsg(13, " checksum rec=%04x comp=%04x\ndata=|%.*s|",
  1082.       check, checkchk, total, data);
  1083.  
  1084.    return(type);
  1085.  
  1086. } /*grpack*/
  1087.  
  1088.  
  1089. /*
  1090.    c h e c k s u m
  1091. */
  1092.  
  1093. static unsigned int checksum(char *data, int len)
  1094. {
  1095.    int i, j;
  1096.    unsigned int tmp, chk1, chk2;
  1097.    chk1 = 0xffff;
  1098.    chk2 = 0;
  1099.    j = len;
  1100.    for (i = 0; i < len; i++) {
  1101.       if (chk1 & 0x8000) {
  1102.          chk1 <<= 1;
  1103.          chk1++;
  1104.       } else {
  1105.          chk1 <<= 1;
  1106.       }
  1107.       tmp = chk1;
  1108.       chk1 += (data[i] & 0xff);
  1109.       chk2 += chk1 ^ j;
  1110.       if ((chk1 & 0xffff) <= (tmp & 0xffff))
  1111.          chk1 ^= chk2;
  1112.       j--;
  1113.    }
  1114.    return(chk1 & 0xffff);
  1115.  
  1116. } /*checksum*/
  1117.  
  1118. gwrmsg(char *str, boolean nowait)
  1119. {
  1120.     char spacket[MAXPACK];
  1121.     int len;
  1122.     len = strlen(str) + 1;
  1123.     if (nowait) {
  1124.         return gsendpkt(str, len);
  1125.     }
  1126.     while (len > pktsize)  {
  1127.         strncpy((char *) spacket, str, pktsize);
  1128.         spacket[pktsize] = '\0';
  1129.         if (gsendpkt((char *) spacket, pktsize)) /* don't re-check len */
  1130.             return(1);
  1131.         str += pktsize;
  1132.         len -= pktsize;
  1133.     }
  1134.     strcpy((char *) spacket, str);
  1135.     if (gsendpkt((char *) spacket, len))
  1136.         return 1;      /* send 'S fromfile tofile user - tofile 0666' */
  1137.     return 0;
  1138. }
  1139.  
  1140. grdmsg(register char *str, int *bytes)
  1141. {
  1142.     return ggetpkt(str, bytes);
  1143. }
  1144.  
  1145.  
  1146.  
  1147.