home *** CD-ROM | disk | FTP | other *** search
/ Super Net 1 / SUPERNET_1.iso / PC / OTROS / EXTRAS / UUCODE / UUPC / TEST / UPC12ES2.ZIP / UUCICO / dcpgpkt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-28  |  61.3 KB  |  1,740 lines

  1. /*--------------------------------------------------------------------*/
  2. /*       d c p g p k t . c                                            */
  3. /*                                                                    */
  4. /*       UUCP 'g' protocol module for UUPC/extended.  Supports 7      */
  5. /*       window variable length packets of up to MAXPACK bytes in     */
  6. /*       length.                                                      */
  7. /*--------------------------------------------------------------------*/
  8.  
  9. /*--------------------------------------------------------------------*/
  10. /*       Stuart Lynne May/87                                          */
  11. /*                                                                    */
  12. /*       Copyright (c) Richard H. Lamb 1985, 1986, 1987               */
  13. /*       Changes Copyright (c) Stuart Lynne 1987                      */
  14. /*                                                                    */
  15. /*    Changes Copyright (c) 1989-1993 by Kendra Electronic            */
  16. /*    Wonderworks.                                                    */
  17. /*                                                                    */
  18. /*    All rights reserved except those explicitly granted by the      */
  19. /*    UUPC/extended license agreement.                                */
  20. /*--------------------------------------------------------------------*/
  21.  
  22. /*--------------------------------------------------------------------*/
  23. /*                          RCS Information                           */
  24. /*--------------------------------------------------------------------*/
  25.  
  26. /*
  27.  *      $Id: dcpgpkt.c 1.23 1993/10/24 12:48:56 ahd Exp $
  28.  *
  29.  *      $Log: dcpgpkt.c $
  30.  * Revision 1.23  1993/10/24  12:48:56  ahd
  31.  * Correct timeouts to user specified, rather than double user specified
  32.  *
  33.  * Revision 1.23  1993/10/24  12:48:56  ahd
  34.  * Correct timeouts to user specified, rather than double user specified
  35.  *
  36.  * Revision 1.22  1993/10/13  01:47:46  ahd
  37.  * Don't NAK upon startup
  38.  *
  39.  * Revision 1.21  1993/10/12  01:32:08  ahd
  40.  * Normalize comments to PL/I style
  41.  *
  42.  * Revision 1.20  1993/10/09  22:21:55  rhg
  43.  * ANSIfy source
  44.  *
  45.  * Revision 1.18  1993/10/04  03:57:20  ahd
  46.  * Drop new lines from start up message
  47.  *
  48.  * Revision 1.17  1993/10/02  22:56:59  ahd
  49.  * Suppress compile warning
  50.  *
  51.  * Revision 1.16  1993/10/02  19:07:49  ahd
  52.  * Treat Windows 3.x ala DOS in handling packets in far memory
  53.  *
  54.  * Revision 1.15  1993/09/20  04:41:54  ahd
  55.  * OS/2 2.x support
  56.  *
  57.  * Revision 1.14  1993/07/22  23:22:27  ahd
  58.  * First pass at changes for Robert Denny's Windows 3.1 support
  59.  *
  60.  * Revision 1.13  1993/05/30  00:01:47  ahd
  61.  * Move UUFAR into header file
  62.  *
  63.  * Revision 1.12  1993/04/13  03:19:45  ahd
  64.  * Only perform copy to gspkt if input to gsendpkt is non-null
  65.  *
  66.  * Revision 1.11  1993/04/13  03:00:05  ahd
  67.  * Correct gspkt declare
  68.  *
  69.  * Revision 1.10  1993/04/13  02:26:30  ahd
  70.  * Move buffers to FAR memory
  71.  *
  72.  * Revision 1.9  1993/04/05  04:32:19  ahd
  73.  * Allow unique send and receive packet sizes
  74.  *
  75.  * Revision 1.8  1993/03/06  23:04:54  ahd
  76.  * Make state names more descriptive
  77.  *
  78.  * Revision 1.7  1992/11/21  05:55:11  ahd
  79.  * Use single bit field for gopenpk flag bits, add debugging info
  80.  *
  81.  * Revision 1.6  1992/11/20  12:38:39  ahd
  82.  * Add additional flags to avoid prematurely ending init sequence
  83.  *
  84.  * Revision 1.5  1992/11/19  03:00:29  ahd
  85.  * drop rcsid
  86.  *
  87.  * Revision 1.4  1992/11/17  13:45:37  ahd
  88.  * Add comments from Ian Talyor
  89.  *
  90.  * Revision 1.3  1992/11/16  02:10:27  ahd
  91.  * Rewrite protocol initialize to insure full exchange of packets
  92.  *
  93.  *          25Aug87 - Allow for up to 7 windows - Jal
  94.  *
  95.  *          01Nov87 - those strncpy's should really be memcpy's! -
  96.  *                    Jal
  97.  *
  98.  *          11Sep89 - Raise TimeOut to 15 - ahd
  99.  *
  100.  *          30Apr90 - Add Jordon Brown's fix for short packet
  101.  *                    retries. Reduce retry limit to 20
  102.  *
  103.  *          22Jul90 - Change error retry limit from per host to per
  104.  *                    packet.
  105.  *
  106.  *          22Jul90 - Add error message for number of retries
  107.  *                    exceeded
  108.  *
  109.  *          08Sep90 - Drop memmove to memcpy change supplied by
  110.  *                    Jordan Brown, MS 6.0 and Turbo C++ agree
  111.  *                    memmove insures no overlap
  112.  */
  113.  
  114. /*--------------------------------------------------------------------*/
  115. /*    Thanks goes to John Gilmore for sending me a copy of Greg       */
  116. /*    Chesson's UUCP protocol description -- Obviously invaluable.    */
  117. /*    Thanks also go to Andrew Tannenbaum for the section on          */
  118. /*    Siding window protocols with a program example in his           */
  119. /*    "Computer Networks" book.                                       */
  120. /*--------------------------------------------------------------------*/
  121.  
  122. /*--------------------------------------------------------------------*/
  123. /*                        System include files                        */
  124. /*--------------------------------------------------------------------*/
  125.  
  126. #include <stdio.h>
  127. #include <string.h>
  128. #include <time.h>
  129. #include <stdlib.h>
  130. #include <ctype.h>
  131.  
  132. #ifdef __TURBOC__
  133. #include <mem.h>
  134. #include <alloc.h>
  135. #else
  136. #include <malloc.h>
  137. #endif
  138.  
  139. /*--------------------------------------------------------------------*/
  140. /*                    UUPC/extended include files                     */
  141. /*--------------------------------------------------------------------*/
  142.  
  143. #include "lib.h"
  144. #include "dcp.h"
  145. #include "dcpsys.h"
  146. #include "dcpgpkt.h"
  147. #include "hostable.h"
  148. #include "security.h"
  149. #include "commlib.h"
  150. #include "modem.h"
  151. #include "catcher.h"
  152.  
  153. /*--------------------------------------------------------------------*/
  154. /*                           Local defines                            */
  155. /*--------------------------------------------------------------------*/
  156.  
  157. #define PKTSIZE   MAXPACK
  158. #define MINPKT    32
  159.  
  160. #define HDRSIZE   6
  161. #define MAXTRY 4
  162.  
  163. #ifndef GDEBUG
  164. #define GDEBUG 4
  165. #endif
  166.  
  167. #ifdef __OS2__
  168. #pragma warn -sig
  169. #endif
  170.  
  171. /*--------------------------------------------------------------------*/
  172. /*    Control whether some buffers are placed outside the default     */
  173. /*    data segment                                                    */
  174. /*--------------------------------------------------------------------*/
  175.  
  176. #ifdef __TURBOC__
  177. #define memavail  coreleft
  178. #else
  179. #define memavail  stackavail
  180. #endif
  181.  
  182. /*--------------------------------------------------------------------*/
  183. /*                     g-packet type definitions                      */
  184. /*--------------------------------------------------------------------*/
  185.  
  186. #define DATA   0
  187. #define CLOSE  1
  188. #define NAK    2
  189. #define SRJ    3
  190. #define ACK    4
  191. #define INITC  5
  192. #define INITB  6
  193. #define INITA  7
  194.  
  195. #define POK    -1
  196.  
  197. #define MAXWINDOW 7
  198. #define NBUF   8              /* always SAME as MAXSEQ ? */
  199. #define MAXSEQ 8
  200.  
  201. typedef enum {
  202.       I_EMPTY,
  203.       I_ERROR,
  204.       I_RESTART,
  205.       I_CALLEE,
  206.       I_CALLER,
  207.       I_GRPACK,
  208.       I_INITA_RECV,
  209.       I_INITA_SEND,
  210.       I_INITB_RECV,
  211.       I_INITB_SEND,
  212.       I_INITC_RECV,
  213.       I_INITC_SEND,
  214.       I_COMPLETE
  215.       } I_STATE;
  216.  
  217. #define between(a,b,c) ((a<=b && b<c) || \
  218.                         (c<a && a<=b) || \
  219.                         (b<c && c<a))
  220.  
  221. #define nextpkt(x)    ((x + 1) % MAXSEQ)
  222. #define nextbuf(x)    ((x + 1) % (nwindows+1))
  223.  
  224. /*--------------------------------------------------------------------*/
  225. /*                 Handle 16 bit vs. 32 bit compilers                 */
  226. /*--------------------------------------------------------------------*/
  227.  
  228. #if defined(BIT32ENV)
  229. #define MEMSET(p,c,l)  memset(p,c,l)
  230. #define MEMCPY(t,s,l)  memcpy(t,s,l)
  231. #define MEMMOVE(t,s,l) memmove(t,s,l)
  232. #else
  233. #define MEMSET(p,c,l)  _fmemset(p,c,l)
  234. #define MEMCPY(t,s,l)  _fmemcpy(t,s,l)
  235. #define MEMMOVE(t,s,l) _fmemmove(t,s,l)
  236. #endif
  237.  
  238. /*--------------------------------------------------------------------*/
  239. /*              Global variables for packet definitions               */
  240. /*--------------------------------------------------------------------*/
  241.  
  242. currentfile();
  243.  
  244. static short irec, lazynak;
  245. static unsigned rwl, rwu, swl, swu;
  246. static unsigned nbuffers;
  247. static unsigned rbl, sbl, sbu;
  248. static KEWSHORT nerr;
  249. static unsigned short outlen[NBUF], inlen[NBUF], xmitlen[NBUF];
  250. static boolean arrived[NBUF];
  251. static unsigned nwindows;
  252.  
  253. static char UUFAR outbuf[NBUF][MAXPACK];
  254. static char UUFAR inbuf[NBUF][MAXPACK];
  255. static time_t ftimer[NBUF];
  256. static short timeouts, outsequence, naksin, naksout, screwups;
  257. static short reinit, shifts, badhdr, resends;
  258. static unsigned char *grpkt = NULL;
  259.  
  260. #if !defined(BIT32ENV)
  261. static char *gspkt = NULL;       /* Local buffer dir                  */
  262. #endif
  263.  
  264. static boolean variablepacket;  /* "v" or in modem file              */
  265.  
  266. static time_t idletimer = 0;
  267.  
  268. /*--------------------------------------------------------------------*/
  269. /*                    Internal function prototypes                    */
  270. /*--------------------------------------------------------------------*/
  271.  
  272. static short initialize(const boolean caller, const char protocol );
  273.  
  274. static short  gmachine(const short timeout);
  275.  
  276. static void gspack(short type,
  277.                    unsigned yyy,
  278.                    unsigned xxx,
  279.                    unsigned len,
  280.                    unsigned xmit,
  281.                    char UUFAR *data);
  282.  
  283. static short  grpack(unsigned *yyy,
  284.                      unsigned *xxx,
  285.                      unsigned *len,
  286.                      char UUFAR *data,
  287.                      const short timeout);
  288.  
  289. static void gstats( void );
  290.  
  291. static unsigned checksum(char *data, unsigned len);
  292.  
  293. /****************** SUB SUB SUB PACKET HANDLER ************/
  294.  
  295. /*--------------------------------------------------------------------*/
  296. /*    g o p e n p k                                                   */
  297. /*                                                                    */
  298. /*    Initialize processing for protocol                              */
  299. /*--------------------------------------------------------------------*/
  300.  
  301. short Gopenpk(const boolean caller)
  302. {
  303.    return initialize(caller , 'G');
  304. } /* Gopenpk */
  305.  
  306. /*--------------------------------------------------------------------*/
  307. /*    v o p e n p k                                                   */
  308. /*                                                                    */
  309. /*    Initialize processing for protocol                              */
  310. /*--------------------------------------------------------------------*/
  311.  
  312. short vopenpk(const boolean caller)
  313. {
  314.    return initialize(caller, 'v');
  315. } /* vopenpk */
  316.  
  317. /*--------------------------------------------------------------------*/
  318. /*    g o p e n p k                                                   */
  319. /*                                                                    */
  320. /*    Initialize processing for protocol                              */
  321. /*--------------------------------------------------------------------*/
  322.  
  323. short gopenpk(const boolean caller)
  324. {
  325.    return initialize(caller, 'g');
  326. } /* vopenpk */
  327.  
  328. /*--------------------------------------------------------------------*/
  329. /*    i n i t i a l i z e                                             */
  330. /*                                                                    */
  331. /*    Initialize processing for protocol                              */
  332. /*--------------------------------------------------------------------*/
  333.  
  334. static short initialize(const boolean caller, const char protocol )
  335. {
  336.    unsigned i, xxx, yyy, len, maxwindows;
  337.  
  338. #define B_SENT_INITA 0x01
  339. #define B_SENT_INITB 0x02
  340. #define B_SENT_INITC 0x04
  341. #define B_RECV_INITA 0x10
  342. #define B_RECV_INITB 0x20
  343. #define B_RECV_INITC 0x40
  344. #define B_INITA (B_SENT_INITA | B_RECV_INITA)
  345. #define B_INITB (B_SENT_INITB | B_RECV_INITB)
  346. #define B_INITC (B_SENT_INITC | B_RECV_INITC)
  347.  
  348.    unsigned flags = 0x00;   /* Init state flags, as defined above  */
  349.  
  350.    I_STATE state;
  351.  
  352. /*--------------------------------------------------------------------*/
  353. /*    Read modem file values for the number of windows and packet     */
  354. /*    sizes                                                           */
  355. /*--------------------------------------------------------------------*/
  356.  
  357.    r_pktsize = s_pktsize = GetGPacket( MAXPACK, protocol );
  358.    maxwindows = GetGWindow(
  359.                      (KEWSHORT) min( MAXWINDOW, RECV_BUF / (s_pktsize+HDRSIZE)),
  360.                      protocol);
  361.  
  362.    variablepacket = bmodemflag[MODEM_VARIABLEPACKET] || (protocol == 'v');
  363.  
  364.    grpkt = malloc( r_pktsize + HDRSIZE );
  365.  
  366. /*--------------------------------------------------------------------*/
  367. /*                     Initialize error counters                      */
  368. /*--------------------------------------------------------------------*/
  369.  
  370.    timeouts = outsequence = naksin = naksout = screwups =
  371.       shifts = badhdr = resends = reinit = 0;
  372.  
  373. /*--------------------------------------------------------------------*/
  374. /*                    Initialize proto parameters                     */
  375. /*--------------------------------------------------------------------*/
  376.  
  377.    nerr = 0;
  378.    nbuffers = 0;
  379.    sbl = swl = swu = sbu = 1;
  380.    rbl = rwl = 0;
  381.    nwindows = maxwindows;
  382.    rwu = nwindows - 1;
  383.  
  384.    for (i = 0; i < NBUF; i++)
  385.    {
  386.       ftimer[i] = 0;
  387.       arrived[i] = FALSE;
  388.    }
  389.  
  390. /*--------------------------------------------------------------------*/
  391. /*                          3-way handshake                           */
  392. /*--------------------------------------------------------------------*/
  393.  
  394. /*--------------------------------------------------------------------*/
  395. /*    The three-way handshake should be independent of who            */
  396. /*    initializes it, but it seems that some versions of uucico       */
  397. /*    assume that the caller sends first and the callee responds.     */
  398. /*    This only matters if we are the callee and the first packet     */
  399. /*    is garbled.  If we send a packet, the other side will assume    */
  400. /*    that we must have seen the packet they sent and will never      */
  401. /*    time out and send it again.  Therefore, if we are the callee    */
  402. /*    we don't send a packet the first time through the loop.         */
  403. /*    This can still fail, but should usually work, and, after        */
  404. /*    all, if the initialization packets are received correctly       */
  405. /*    there will be no problem no matter what we do.                  */
  406. /*                                                                    */
  407. /*    (The above quoted verbatim from Ian Taylor)                     */
  408. /*--------------------------------------------------------------------*/
  409.  
  410.    state = caller ? I_CALLER : I_CALLEE;
  411.  
  412. /*--------------------------------------------------------------------*/
  413. /*    Exchange initialization messages with the other system.         */
  414. /*                                                                    */
  415. /*    A problem:                                                      */
  416. /*                                                                    */
  417. /*    We send INITA; it gets received                                 */
  418. /*    We receive INITA                                                */
  419. /*    We send INITB; it gets garbled                                  */
  420. /*    We receive INITB                                                */
  421. /*                                                                    */
  422. /*    We have seen and sent INITB, so we start to send INITC.  The    */
  423. /*    other side as sent INITB but not seen it, so it times out       */
  424. /*    and resends INITB.  We will continue sending INITC and the      */
  425. /*    other side will continue sending INITB until both sides give    */
  426. /*    up and start again with INITA.                                  */
  427. /*                                                                    */
  428. /*    It might seem as though if we are sending INITC and receive     */
  429. /*    INITB, we should resend our INITB, but this could cause         */
  430. /*    infinite echoing of INITB on a long-latency line.  Rather       */
  431. /*    than risk that, I have implemented a fast drop-back             */
  432. /*    procedure.  If we are sending INITB and receive INITC, the      */
  433. /*    other side has gotten ahead of us.  We immediately fail and     */
  434. /*    begin again with INITA.  For the other side, if we are          */
  435. /*    sending INITC and see INITA, we also immediately fail back      */
  436. /*    to INITA.                                                       */
  437. /*                                                                    */
  438. /*    Unfortunately, this doesn't work for the other case, in         */
  439. /*    which we are sending INITB but the other side has not yet       */
  440. /*    seen INITA.  As far as I can see, if this happens we just       */
  441. /*    have to wait until we time out and resend INITA.                */
  442. /*                                                                    */
  443. /*    (The above also quoted verbatim from Ian Taylor; however, the   */
  444. /*    code and associated bugs are all Drew's)                        */
  445. /*--------------------------------------------------------------------*/
  446.  
  447. /*--------------------------------------------------------------------*/
  448. /*    A note about the games with the variable "flags", which is      */
  449. /*    bit twiddled alot below.  The statement below:                  */
  450. /*                                                                    */
  451. /*          flags = (flags & B_SENT_INITA) | B_RECV_INITA;            */
  452. /*                                                                    */
  453. /*    works to turn off all the bits in flags except B_SENT_INITA     */
  454. /*    if it was already on, and then turns on flag B_RECV_INITA.      */
  455. /*    We use statements like this to reset most of the flags at       */
  456. /*    once, leaving one or two bits on; this in turn allows us to     */
  457. /*    check in later states that the previous two states were the     */
  458. /*    expected ones.                                                  */
  459. /*                                                                    */
  460. /*    Likewise, the following statement:                              */
  461. /*                                                                    */
  462. /*          state = (flags & B_SENT_INITA) ?                          */
  463. /*                         I_INITB_SEND : I_INITA_SEND;               */
  464. /*                                                                    */
  465. /*    tests to see if B_SENT_INITA was already set, and return the    */
  466. /*    "true" condition (I_INITB_SEND) otherwise return the "false"    */
  467. /*    (I_INITA_SEND).                                                 */
  468. /*--------------------------------------------------------------------*/
  469.  
  470.    while( state != I_COMPLETE )
  471.    {
  472.       printmsg(4, "gopenpk: I State = %2d, flag = 0x%02x",
  473.                (int) state, (int) flags);
  474.  
  475.       switch( state )
  476.       {
  477.  
  478. /*--------------------------------------------------------------------*/
  479. /*                          Receive a packet                          */
  480. /*--------------------------------------------------------------------*/
  481.  
  482.          case I_GRPACK:
  483.             switch (grpack(&yyy, &xxx, &len, NULL, M_gPacketTimeout ))
  484.             {
  485.  
  486.                case INITA:
  487.                   printmsg(5, "**got INITA");
  488.                   state = I_INITA_RECV;
  489.                   break;
  490.  
  491.                case INITB:
  492.                   printmsg(5, "**got INITB");
  493.                   state = I_INITB_RECV;
  494.                   break;
  495.  
  496.                case INITC:
  497.                   printmsg(5, "**got INITC");
  498.                   state = I_INITC_RECV;
  499.                   break;
  500.  
  501.                case DCP_EMPTY:
  502.                   printmsg(GDEBUG, "**got EMPTY");
  503.                   state = I_EMPTY;
  504.  
  505.                   if (bmodemflag[MODEM_CD] && !CD())
  506.                   {
  507.                      printmsg(0,"gopenpk: Modem carrier lost");
  508.                      return DCP_FAILED;
  509.                   }
  510.                   break;
  511.  
  512.                case CLOSE:
  513.                   printmsg(GDEBUG, "**got CLOSE");
  514.                   gspack(CLOSE, 0, 0, 0, 0, NULL);
  515.                   return DCP_FAILED;
  516.  
  517.                default:
  518.                   printmsg(GDEBUG, "**got SCREW UP");
  519.                   state = I_ERROR;
  520.                   break;
  521.             }
  522.  
  523.             if (bmodemflag[MODEM_CD] && !CD())
  524.             {
  525.                printmsg(0,"gopenpk: Modem carrier lost");
  526.                return DCP_FAILED;
  527.             }
  528.             break;
  529.  
  530. /*--------------------------------------------------------------------*/
  531. /*                         Initialize states                          */
  532. /*--------------------------------------------------------------------*/
  533.  
  534.          case I_CALLER:
  535.             state = I_INITA_SEND;
  536.             break;
  537.  
  538.          case I_CALLEE:
  539.             state = I_GRPACK;
  540.             break;
  541.  
  542. /*--------------------------------------------------------------------*/
  543. /*                  Process received or sent packets                  */
  544. /*--------------------------------------------------------------------*/
  545.  
  546.          case I_INITA_RECV:
  547.             if (yyy < nwindows)
  548.             {
  549.                nwindows = yyy;
  550.                rwu = nwindows - 1;
  551.             }
  552.             flags = (flags & B_SENT_INITA) | B_RECV_INITA;
  553.             state = (flags & B_SENT_INITA) ? I_INITB_SEND : I_INITA_SEND;
  554.             break;
  555.  
  556.          case I_INITA_SEND:
  557.             gspack(INITA, 0, 0, 0, nwindows, NULL);
  558.             flags = (flags & B_RECV_INITA) | B_SENT_INITA;
  559.             state = I_GRPACK;
  560.             break;
  561.  
  562.          case I_INITB_RECV:
  563.             if ((flags & (B_RECV_INITA | B_SENT_INITA)) ==
  564.                          (B_RECV_INITA | B_SENT_INITA))
  565.             {
  566.                i = 32 << yyy;
  567.                if (i < s_pktsize)
  568.                   s_pktsize = i;
  569.                flags = (flags & B_SENT_INITB) | B_RECV_INITB;
  570.                state = (flags & B_SENT_INITB) ? I_INITC_SEND : I_INITB_SEND;
  571.             } /* if */
  572.             else
  573.                state = I_RESTART;
  574.             break;
  575.  
  576.          case I_INITB_SEND:
  577.             gspack(INITB, 0, 0, 0, r_pktsize, NULL);
  578.                                        /* Data segment (packet) size   */
  579.             flags = (flags & (B_INITA | B_RECV_INITB)) | B_SENT_INITB;
  580.             state = I_GRPACK;
  581.             break;
  582.  
  583.          case I_INITC_RECV:
  584.             if ((flags & (B_RECV_INITB | B_SENT_INITB)) ==
  585.                            (B_RECV_INITB | B_SENT_INITB))
  586.             {
  587.                if (yyy < nwindows)
  588.                {
  589.                   printmsg(0,"Unexpected INITC window size of %d",
  590.                              nwindows );
  591.                   nwindows = yyy;
  592.                   rwu = nwindows - 1;
  593.                }
  594.                flags = (flags & B_SENT_INITC) | B_RECV_INITC;
  595.                state = (flags & B_SENT_INITC) ? I_COMPLETE : I_INITC_SEND;
  596.             }
  597.             else
  598.                state = I_RESTART;
  599.             break;
  600.  
  601.          case I_INITC_SEND:
  602.             gspack(INITC, 0, 0, 0, nwindows, NULL);
  603.             flags = (flags & (B_INITB | B_RECV_INITC)) | B_SENT_INITC;
  604.             state = (flags & B_RECV_INITC) ? I_COMPLETE : I_GRPACK;
  605.             break;
  606.  
  607. /*--------------------------------------------------------------------*/
  608. /*                            Error states                            */
  609. /*--------------------------------------------------------------------*/
  610.  
  611.          case I_EMPTY:
  612.             timeouts++;
  613.             state = I_RESTART;
  614.             break;
  615.  
  616.          case I_ERROR:
  617.             screwups++;
  618.             state = I_RESTART;
  619.             break;
  620.  
  621.          case I_RESTART:
  622.             printmsg(2,"gopenpk: Restarting initialize sequence");
  623.             nerr++;
  624.             flags = 0x00;
  625.             state = I_INITA_SEND;
  626.             break;
  627.  
  628.       } /* switch */
  629.  
  630.       if ( terminate_processing )
  631.       {
  632.          printmsg(0,"gopenpk: Terminated by user");
  633.          return DCP_FAILED;
  634.       }
  635.  
  636.       if (nerr >= M_MaxErr)
  637.       {
  638.          remote_stats.errors += nerr;
  639.          nerr = 0;
  640.          printmsg(0,
  641.             "gopenpk: Consecutive error limit of %ld exceeded, "
  642.                      "%ld total errors",
  643.              (long) M_MaxErr, remote_stats.errors);
  644.          return(DCP_FAILED);
  645.       }
  646.    } /* while */
  647.  
  648. /*--------------------------------------------------------------------*/
  649. /*                    Allocate the needed buffers                     */
  650. /*--------------------------------------------------------------------*/
  651.  
  652.    grpkt = realloc( grpkt, r_pktsize + HDRSIZE );
  653.    checkref( grpkt );
  654.  
  655. #if !defined(BIT32ENV)
  656.    gspkt = malloc( s_pktsize );
  657.    checkref( gspkt );
  658. #endif
  659.  
  660.    nerr = 0;
  661.    lazynak = 0;
  662.  
  663. #if defined(BIT32ENV) || defined(_Windows)
  664.    printmsg(2,"%s packets, "
  665.               "Window size %d, "
  666.               "Receive packet %d, "
  667.               "Send packet %d",
  668.             variablepacket ? "Variable" : "Fixed",
  669.             nwindows,
  670.             r_pktsize,
  671.             s_pktsize );
  672. #else
  673.    printmsg(2,"%s packets, "
  674.               "Window size %d, "
  675.               "Receive packet %d, "
  676.               "Send packet %d, "
  677.               "Memory avail %u",
  678.             variablepacket ? "Variable" : "Fixed",
  679.             nwindows,
  680.             r_pktsize,
  681.             s_pktsize,
  682.             memavail());
  683. #endif
  684.  
  685.    time( &idletimer );              /* Flag our link has been used   */
  686.  
  687.    return(DCP_OK);                  /* Channel open to caller        */
  688.  
  689. } /*initialize*/
  690.  
  691. /*--------------------------------------------------------------------*/
  692. /*    g f i l e p k t                                                 */
  693. /*                                                                    */
  694. /*    Begin a file transfer (not used by "g" protocol)                */
  695. /*--------------------------------------------------------------------*/
  696.  
  697. short gfilepkt( void )
  698. {
  699.  
  700.    return DCP_OK;
  701.  
  702. } /* gfilepkt */
  703.  
  704. /*--------------------------------------------------------------------*/
  705. /*    g c l o s e p k                                                 */
  706. /*                                                                    */
  707. /*    Close packet machine                                            */
  708. /*--------------------------------------------------------------------*/
  709.  
  710. short gclosepk()
  711. {
  712.    unsigned i;
  713.  
  714.    for (i = 0; i < MAXTRY; i++)
  715.    {
  716.       gspack(CLOSE, 0, 0, 0, 0, NULL);
  717.       if (gmachine(M_gPacketTimeout) == CLOSE)
  718.          break;
  719.    } /* for (i = 0; i < MAXTRY; i++) */
  720.  
  721. /*--------------------------------------------------------------------*/
  722. /*                        Release our buffers                         */
  723. /*--------------------------------------------------------------------*/
  724.  
  725.    free( grpkt );
  726.    grpkt = NULL;
  727.  
  728. #if !defined(BIT32ENV)
  729.    free( gspkt );
  730.    gspkt = NULL;
  731. #endif
  732.  
  733. /*--------------------------------------------------------------------*/
  734. /*                Report the results of our adventures                */
  735. /*--------------------------------------------------------------------*/
  736.  
  737.    gstats();
  738.  
  739. /*--------------------------------------------------------------------*/
  740. /*                          Return to caller                          */
  741. /*--------------------------------------------------------------------*/
  742.  
  743.    return(0);
  744.  
  745. } /*gclosepk*/
  746.  
  747. /*--------------------------------------------------------------------*/
  748. /*    g s t a t s                                                     */
  749. /*                                                                    */
  750. /*    Report summary of errors for processing                         */
  751. /*--------------------------------------------------------------------*/
  752.  
  753. static void gstats( void )
  754. {
  755.    remote_stats.errors += nerr;
  756.    nerr = 0;
  757.    if ( remote_stats.errors || badhdr )
  758.    {
  759.       printmsg(0,
  760.          "%d time outs, %d port reinits, %d out of seq pkts, "
  761.          "%d NAKs rec, %d NAKs sent",
  762.             timeouts, reinit, outsequence, naksin, naksout);
  763.       printmsg(0,
  764.          "%d invalid pkt types, %d re-syncs, %d bad pkt hdrs, %d pkts resent",
  765.             screwups, shifts, badhdr, resends);
  766.    } /* if ( remote_stats.errors || shifts || badhdr ) */
  767. } /* gstats */
  768.  
  769. /*--------------------------------------------------------------------*/
  770. /*    g g e t p k t                                                   */
  771. /*                                                                    */
  772. /*    Gets no more than a packet's worth of data from                 */
  773. /*    the "packet I/O state machine".  May have to                    */
  774. /*    periodically run the packet machine to get some packets.        */
  775. /*                                                                    */
  776. /*    on input:   don't care                                          */
  777. /*    on return:  data+\0 and length in len.                          */
  778. /*                                                                    */
  779. /*    ret(0)   if all's well                                          */
  780. /*    ret(-1) if problems (failed)                                    */
  781. /*--------------------------------------------------------------------*/
  782.  
  783. short ggetpkt(char *data, short *len)
  784. {
  785.    short   retry = M_MaxErr;
  786.    time_t start;
  787. #ifdef _DEBUG
  788.    short savedebug = debuglevel;
  789. #endif
  790.  
  791.    irec = 1;
  792.    checkref( data );
  793.  
  794. /*--------------------------------------------------------------------*/
  795. /*                Loop to wait for the desired packet                 */
  796. /*--------------------------------------------------------------------*/
  797.  
  798.    time( &start );
  799.    while (!arrived[rbl] && retry)
  800.    {
  801.       if (gmachine(M_gPacketTimeout) != POK)
  802.          return(-1);
  803.  
  804.       if (!arrived[rbl] )
  805.       {
  806.          time_t now;
  807.  
  808.          if (time( &now ) >= (start + M_gPacketTimeout) )
  809.          {
  810. #ifdef _DEBUG
  811.             if ( debuglevel < 6 )
  812.                debuglevel = 6;
  813. #endif
  814.             printmsg(GDEBUG,
  815.                      "ggetpkt: Timeout %d waiting for inbound packet %d",
  816.                      M_MaxErr - --retry, remote_stats.packets + 1);
  817.             timeouts++;
  818.             start = now;
  819.          } /* if (time( now ) > (start + M_gPacketTimeout) ) */
  820.  
  821.       } /* if (!arrived[rbl] ) */
  822.  
  823.    } /* while (!arrived[rbl] && retry) */
  824.  
  825. #ifdef _DEBUG
  826.    debuglevel = savedebug;
  827. #endif
  828.  
  829.    if (!arrived[rbl])
  830.    {
  831.       printmsg(0,"ggetpkt: Remote host failed to respond after %ld seconds",
  832.                (long) M_gPacketTimeout * M_MaxErr);
  833.       gclosepk();
  834.       return -1;
  835.    }
  836.  
  837. /*--------------------------------------------------------------------*/
  838. /*                           Got a packet!                            */
  839. /*--------------------------------------------------------------------*/
  840.  
  841.    *len = inlen[rbl];
  842.    MEMCPY(data, inbuf[rbl], *len);
  843.  
  844.    arrived[rbl] = FALSE;      /* Buffer is now emptied               */
  845.    rwu = nextpkt(rwu);        /* bump receive window                 */
  846.  
  847.    return(0);
  848.  
  849. } /*ggetpkt*/
  850.  
  851. /*--------------------------------------------------------------------*/
  852. /*       g s e n d p k t                                              */
  853. /*                                                                    */
  854. /*       Put at most a packet's worth of data in the packet state     */
  855. /*       machine for transmission.  May have to run the packet        */
  856. /*       machine a few times to get an available output slot.         */
  857. /*                                                                    */
  858. /*       on input: data=*data; len=length of data in data.            */
  859. /*                                                                    */
  860. /*       return:                                                      */
  861. /*        0 if all's well                                             */
  862. /*       -1 if problems (failed)                                      */
  863. /*--------------------------------------------------------------------*/
  864.  
  865. short gsendpkt(char *data, short len)
  866. {
  867.    int delta;
  868. #ifdef _DEBUG
  869.    short savedebug = debuglevel;
  870. #endif
  871.  
  872.    checkref( data );
  873.    irec = 0;
  874.  
  875. #ifdef UDEBUG
  876.    printmsg(5,"Sending %d bytes from %p", (int) len, data);
  877. #endif
  878.  
  879. /*--------------------------------------------------------------------*/
  880. /*       WAIT FOR INPUT i.e. if we have sent SWINDOW pkts and none    */
  881. /*       have been acked, wait for acks.  Note that we always go      */
  882. /*       through the machine at least once to keep caught up with     */
  883. /*       ACK's sent by remote machine.                                */
  884. /*--------------------------------------------------------------------*/
  885.  
  886.    if ( nbuffers )
  887.    do {
  888.       if (gmachine(0) != POK)    /* Spin with no timeout             */
  889.          return(-1);
  890.    } while (nbuffers >= nwindows);
  891.  
  892. /*--------------------------------------------------------------------*/
  893. /*               Place packet in table and mark unacked               */
  894. /*--------------------------------------------------------------------*/
  895.  
  896.    MEMCPY(outbuf[sbu], data, len);
  897.  
  898. /*--------------------------------------------------------------------*/
  899. /*                       Handle short packets.                        */
  900. /*--------------------------------------------------------------------*/
  901.  
  902.    xmitlen[sbu] = (unsigned short) s_pktsize;
  903.    if (variablepacket)
  904.       while ( ((len * 2) < (short) xmitlen[sbu]) && (xmitlen[sbu] > MINPKT) )
  905.          xmitlen[sbu] /= 2;
  906.  
  907.    if ( xmitlen[sbu] < MINPKT )
  908.    {
  909.       printmsg(0,"gsendpkt: Bad packet size %d, "
  910.                "data length %d",
  911.                xmitlen[sbu], len);
  912.       xmitlen[sbu] = MINPKT;
  913.    }
  914.  
  915.    delta = xmitlen[sbu] - len;
  916.    if (delta > 127)
  917.    {
  918.       MEMMOVE(outbuf[sbu] + 2, outbuf[sbu], len);
  919.       MEMSET(outbuf[sbu]+len+2, 0, delta - 2);
  920.                               /* Pad with nulls.  Ugh.               */
  921.       outbuf[sbu][0] = (unsigned char) ((delta & 0x7f) | 0x80);
  922.       outbuf[sbu][1] = (unsigned char) (delta >> 7);
  923.    } /* if (delta > 127) */
  924.    else if (delta > 0 )
  925.    {
  926.       MEMMOVE(outbuf[sbu] + 1, outbuf[sbu], len);
  927.       outbuf[sbu][0] = (unsigned char) delta;
  928.       MEMSET(outbuf[sbu]+len+1, 0, delta - 1);
  929.                               /* Pad with nulls.  Ugh.               */
  930.    } /* else if (delta > 0 )  */
  931.  
  932. /*--------------------------------------------------------------------*/
  933. /*                            Mark packet                             */
  934. /*--------------------------------------------------------------------*/
  935.  
  936.    outlen[sbu] = len;
  937.    ftimer[sbu] = time(nil(time_t));
  938.    nbuffers++;
  939.  
  940. /*--------------------------------------------------------------------*/
  941. /*                              send it                               */
  942. /*--------------------------------------------------------------------*/
  943.  
  944.    gspack(DATA, rwl, swu, outlen[sbu], xmitlen[sbu], outbuf[sbu]);
  945.  
  946.    swu = nextpkt(swu);        /* Bump send window                    */
  947.    sbu = nextbuf( sbu );      /* Bump to next send buffer            */
  948.  
  949. #ifdef _DEBUG
  950.    debuglevel = savedebug;
  951. #endif
  952.  
  953.    return(0);
  954.  
  955. } /*gsendpkt*/
  956.  
  957. /*--------------------------------------------------------------------*/
  958. /*    g e o f p k t                                                   */
  959. /*                                                                    */
  960. /*    Transmit EOF to the other system                                */
  961. /*--------------------------------------------------------------------*/
  962.  
  963. short geofpkt( void )
  964. {
  965.    if ((*sendpkt)("", 0))          /* Empty packet == EOF             */
  966.       return DCP_FAILED;
  967.    else
  968.       return DCP_OK;
  969. } /* geofpkt */
  970.  
  971. /*--------------------------------------------------------------------*/
  972. /*    g w r m s g                                                     */
  973. /*                                                                    */
  974. /*    Send a message to remote system                                 */
  975. /*--------------------------------------------------------------------*/
  976.  
  977. short gwrmsg( char *s )
  978. {
  979.    for( ; strlen(s) >= s_pktsize; s += s_pktsize)
  980.    {
  981.       short result = (*sendpkt)(s, (short) s_pktsize);
  982.       if (result)
  983.          return result;
  984.    }
  985.  
  986.    return (*sendpkt)(s, (short) (strlen(s) + 1));
  987.  
  988. } /* gwrmsg */
  989.  
  990. /*--------------------------------------------------------------------*/
  991. /*    g r d m s g                                                     */
  992. /*                                                                    */
  993. /*    Read a message from the remote system                           */
  994. /*--------------------------------------------------------------------*/
  995.  
  996. short grdmsg( char *s)
  997. {
  998.    for ( ;; )
  999.    {
  1000.       short len;
  1001.       short result = (*getpkt)( s, &len );
  1002.       if (result || (s[len-1] == '\0'))
  1003.          return result;
  1004.       s += len;
  1005.    } /* for */
  1006.  
  1007. } /* grdmsg */
  1008.  
  1009. /**********  Packet Machine  ********** RH Lamb 3/87 */
  1010.  
  1011. /*--------------------------------------------------------------------*/
  1012. /*    g m a c h i n e                                                 */
  1013. /*                                                                    */
  1014. /*    Ideally we would like to fork this process off in an            */
  1015. /*    infinite loop and send and receive packets through "inbuf"      */
  1016. /*    and "outbuf".  Can't do this in MS-DOS so we setup "getpkt"     */
  1017. /*    and "sendpkt" to call this routine often and return only        */
  1018. /*    when the input buffer is empty thus "blocking" the packet-      */
  1019. /*    machine task.                                                   */
  1020. /*--------------------------------------------------------------------*/
  1021.  
  1022. static short gmachine(const short timeout )
  1023. {
  1024.  
  1025.    boolean done   = FALSE;    /* True = drop out of machine loop  */
  1026.    boolean close  = FALSE;    /* True = terminate connection upon
  1027.                                         exit                      */
  1028.    boolean inseq  = TRUE;     /* True = Count next out of sequence
  1029.                                         packet as an error           */
  1030.    while ( !done )
  1031.    {
  1032.       boolean resend = FALSE;    /* True = resend data packets       */
  1033.       boolean donak  = FALSE;    /* True = NAK the other system      */
  1034.       unsigned long packet_no = remote_stats.packets;
  1035.  
  1036.       short pkttype;
  1037.       unsigned rack, rseq, rlen, rbuf, i1;
  1038.       time_t now;
  1039.  
  1040.       if ( debuglevel >= 10 )    /* Optimize processing a little bit */
  1041.       {
  1042.  
  1043.          printmsg(10, "* send %d %d < W < %d %d, "
  1044.                       "receive %d %d < W < %d, "
  1045.                       "error %d, packet %d",
  1046.             swl, sbl, swu, sbu, rwl, rbl, rwu, nerr,
  1047.             (long) remote_stats.packets);
  1048.  
  1049. /*--------------------------------------------------------------------*/
  1050. /*    Waiting for ACKs for swl to swu-1.  Next pkt to send=swu        */
  1051. /*    rwl=expected pkt                                                */
  1052. /*--------------------------------------------------------------------*/
  1053.  
  1054.       }
  1055.  
  1056. /*--------------------------------------------------------------------*/
  1057. /*             Attempt to retrieve a packet and handle it             */
  1058. /*--------------------------------------------------------------------*/
  1059.  
  1060.       pkttype = grpack(&rack, &rseq, &rlen, inbuf[nextbuf(rbl)], timeout);
  1061.       time(&now);
  1062.       switch (pkttype) {
  1063.  
  1064.          case CLOSE:
  1065.             remote_stats.packets++;
  1066.             printmsg(GDEBUG, "**got CLOSE");
  1067.             close = done = TRUE;
  1068.             break;
  1069.  
  1070.          case DCP_EMPTY:
  1071.             printmsg(timeout ? GDEBUG : 8, "**got EMPTY");
  1072.  
  1073.             if (bmodemflag[MODEM_CD] && !CD())
  1074.             {
  1075.                printmsg(0,"gmachine: Modem carrier lost");
  1076.                nerr++;
  1077.                close = TRUE;
  1078.             }
  1079.  
  1080.             if ( terminate_processing )
  1081.             {
  1082.                printmsg(0,"gmachine: User aborted processing");
  1083.                close = TRUE;
  1084.             }
  1085.  
  1086.             if (ftimer[sbl])
  1087.             {
  1088. #ifdef UDEBUG
  1089.                printmsg(6, "---> seq, elapst %d %ld", sbl,
  1090.                     ftimer[sbl] - now);
  1091. #endif
  1092.                if ( ftimer[sbl] <= (now - M_gPacketTimeout))
  1093.                {
  1094.                    printmsg(4, "*** timeout %d (%ld)",
  1095.                                sbl, (long) remote_stats.packets);
  1096.                        /* Since "g" is "go-back-N", when we time out we
  1097.                           must send the last N pkts in order.  The generalized
  1098.                           sliding window scheme relaxes this reqirment. */
  1099.                    nerr++;
  1100.                    timeouts++;
  1101.                    resend = TRUE;
  1102.                } /* if */
  1103.             } /* if */
  1104.             else if ( now >= (idletimer + M_gPacketTimeout))
  1105.                donak = TRUE;
  1106.  
  1107.             done = TRUE;
  1108.             break;
  1109.  
  1110.          case DATA:
  1111.             printmsg(5, "**got DATA %d %d", rack, rseq);
  1112.             i1 = nextpkt(rwl);   /* (R+1)%8 <-- -->(R+W)%8 */
  1113.             if (i1 == rseq) {
  1114.                lazynak--;
  1115.                remote_stats.packets++;
  1116.                idletimer = now;
  1117.                rwl = i1;
  1118.                rbl = nextbuf( rbl );
  1119.                inseq = arrived[rbl] = TRUE;
  1120.                inlen[rbl] = (unsigned short) rlen;
  1121.                printmsg(5, "*** ACK d %d %d", rwl, rbl);
  1122.                gspack(ACK, rwl, 0, 0, 0, NULL);
  1123.                done = TRUE;   /* return to caller when finished      */
  1124.                               /* in a mtask system, unneccesary      */
  1125.             } else {
  1126.                if (inseq || ( now >= (idletimer + M_gPacketTimeout)))
  1127.                {
  1128.                   donak = TRUE;  /* Only flag first out of sequence
  1129.                                     packet as error, since we know
  1130.                                     following ones also bad            */
  1131.                   outsequence++;
  1132.                   inseq = FALSE;
  1133.                }
  1134.                printmsg(GDEBUG, "*** unexpect %d ne %d (%d - %d)",
  1135.                                        rseq, i1, rwl, rwu);
  1136.             } /* else */
  1137.  
  1138.             if ( swl == swu )       /* We waiting for an ACK?     */
  1139.                break;               /* No --> Skip ACK processing */
  1140.             /* else Fall through to ACK case */
  1141.  
  1142.          case NAK:
  1143.          case ACK:
  1144.             if (pkttype == NAK)
  1145.             {
  1146.                nerr++;
  1147.                naksin++;
  1148.                printmsg(5, "**got NAK %d", rack);
  1149.                resend = TRUE;
  1150.             }
  1151.             else if (pkttype == ACK)
  1152.                printmsg(5, "**got ACK %d", rack);
  1153.  
  1154.             while(between(swl, rack, swu))
  1155.             {                             /* S<-- -->(S+W-1)%8 */
  1156.                remote_stats.packets++;
  1157.                printmsg(5, "*** ACK %d", swl);
  1158.                ftimer[sbl] = 0;
  1159.                idletimer = now;
  1160.                nbuffers--;
  1161.                done = TRUE;            /* Get more data for input */
  1162.                swl = nextpkt(swl);
  1163.                sbl = nextbuf(sbl);
  1164.             } /* while */
  1165.  
  1166.             if (!done && (pkttype == ACK)) /* Find packet?         */
  1167.             {
  1168.                printmsg(GDEBUG,"*** ACK for bad packet %d (%d - %d)",
  1169.                            rack, swl, swu);
  1170.             } /* if */
  1171.             break;
  1172.  
  1173.          case DCP_ERROR:
  1174.             printmsg(GDEBUG, "*** got BAD CHK");
  1175.             naksout++;
  1176.             donak = TRUE;
  1177.             lazynak = 0;               /* Always NAK bad checksum */
  1178.             break;
  1179.  
  1180.          default:
  1181.             screwups++;
  1182.             nerr++;
  1183.             printmsg(GDEBUG, "*** got SCREW UP");
  1184.             break;
  1185.  
  1186.       } /* switch */
  1187.  
  1188. /*--------------------------------------------------------------------*/
  1189. /*      If we received an NAK or timed out, resend data packets       */
  1190. /*--------------------------------------------------------------------*/
  1191.  
  1192.       if ( resend )
  1193.       for (rack = swl,
  1194.            rbuf = sbl;
  1195.            between(swl, rack, swu);
  1196.            rack = nextpkt(rack), rbuf = nextbuf( rbuf ))
  1197.       {                          /* resend rack->(swu-1)             */
  1198.          resends++;
  1199.  
  1200.          if ( outbuf[rbuf] == NULL )
  1201.          {
  1202.             printmsg(0,"gmachine: Transmit of NULL packet (%d %d)",
  1203.                      rwl, rbuf);
  1204.             panic();
  1205.          }
  1206.  
  1207.          if ( xmitlen[rbuf] == 0 )
  1208.          {
  1209.             printmsg(0,"gmachine: Transmit of 0 length packet (%d %d)",
  1210.                      rwl, rbuf);
  1211.             panic();
  1212.          }
  1213.  
  1214.          gspack(DATA, rwl, rack, outlen[rbuf], xmitlen[rbuf], outbuf[rbuf]);
  1215.          printmsg(5, "*** resent %d", rack);
  1216.          idletimer = ftimer[rbuf] = now;
  1217.       } /* for */
  1218.  
  1219. /*--------------------------------------------------------------------*/
  1220. /*       If we have an error and have not recently sent a NAK, do     */
  1221. /*       so now.  We then reset our counter so we receive at least    */
  1222. /*       a window full of packets before sending another NAK          */
  1223. /*--------------------------------------------------------------------*/
  1224.  
  1225.       if ( donak )
  1226.       {
  1227.          nerr++;
  1228.          if ( (lazynak < 1) || (now >= (idletimer + M_gPacketTimeout)))
  1229.          {
  1230.             printmsg(5, "*** NAK d %d", rwl);
  1231.             gspack(NAK, rwl, 0, 0, 0, NULL);
  1232.             naksout++;
  1233.             idletimer = now;
  1234.             lazynak = (short) (nwindows + 1);
  1235.          } /* if ( lazynak < 1 ) */
  1236.       } /* if ( donak ) */
  1237.  
  1238. /*--------------------------------------------------------------------*/
  1239. /*                   Update error counter if needed                   */
  1240. /*--------------------------------------------------------------------*/
  1241.  
  1242.       if ((close || (packet_no != remote_stats.packets)) && (nerr > 0))
  1243.       {
  1244.          printmsg(GDEBUG,"gmachine: Packet %ld had %ld errors during transfer",
  1245.                      remote_stats.packets, (long) nerr);
  1246.          remote_stats.errors += nerr;
  1247.          nerr = 0;
  1248.       }
  1249.  
  1250. /*--------------------------------------------------------------------*/
  1251. /*    If we have an excessive number of errors, drop out of the       */
  1252. /*    loop                                                            */
  1253. /*--------------------------------------------------------------------*/
  1254.  
  1255.       if (nerr >= M_MaxErr)
  1256.       {
  1257.          printmsg(0,
  1258.             "gmachine: Consecutive error limit of %d exceeded, %d total errors",
  1259.             M_MaxErr, nerr + remote_stats.errors);
  1260.          done = close = TRUE;
  1261.          gstats();
  1262.       }
  1263.    } /* while */
  1264.  
  1265. /*--------------------------------------------------------------------*/
  1266. /*    Return to caller, gracefully terminating packet machine if      */
  1267. /*    requested                                                       */
  1268. /*--------------------------------------------------------------------*/
  1269.  
  1270. #ifdef UDEBUG
  1271.    printmsg(5,"gmachine: Exit %s", close ? "closed" : "open");
  1272. #endif
  1273.  
  1274.    if ( close )
  1275.    {
  1276.       gspack(CLOSE, 0, 0, 0, 0, NULL);
  1277.       return CLOSE;
  1278.    }
  1279.    else
  1280.       return POK;
  1281.  
  1282. } /*gmachine*/
  1283.  
  1284. /*************** FRAMING *****************************/
  1285.  
  1286. /*
  1287.    g s p a c k
  1288.  
  1289.    Send a packet
  1290.  
  1291.    type=type yyy=pkrec xxx=timesent len=length<=s_pktsize data=*data
  1292.    ret(0) always
  1293. */
  1294.  
  1295. static void gspack(short type,
  1296.                    unsigned yyy,
  1297.                    unsigned xxx,
  1298.                    unsigned len,
  1299.                    unsigned xmit,
  1300. #if defined(BIT32ENV)
  1301.                    char *data)
  1302. #else
  1303.                    char UUFAR *input)
  1304. #endif
  1305. {
  1306.    unsigned check, i;
  1307.    unsigned char header[HDRSIZE];
  1308.  
  1309. #if !defined(BIT32ENV)
  1310.    char *data;                   /* Local data buffer address         */
  1311.    if ( input == NULL )
  1312.       data = NULL;               /* Make consistent with real buffer  */
  1313.    else {                        /* Only copy if non-NULL              */
  1314.       data = gspkt;
  1315.       MEMCPY( data, input, xmit );
  1316.    }
  1317. #endif
  1318.  
  1319. #ifdef   LINKTEST
  1320.    /***** Link Testing Mods *****/
  1321.    unsigned char dpkerr[10];
  1322.    /***** End Link Testing Mods *****/
  1323. #endif   /* LINKTEST */
  1324.  
  1325. #ifdef   LINKTEST
  1326.    /***** Link Testing Mods - create artificial errors *****/
  1327.    printf("**n:normal,e:error,l:lost,p:partial,h:bad header,s:new seq--> ");
  1328.    gets(dpkerr);
  1329.    if (dpkerr[0] == 's')
  1330.       sscanf(&dpkerr[1], "%d", &xxx);
  1331.    /***** End Link Testing Mods *****/
  1332. #endif   /* LINKTEST */
  1333.  
  1334.    if ( debuglevel > 4 )
  1335.       printmsg(5, "send packet type %d, yyy=%d, xxx=%d, len=%d, buf = %d",
  1336.                type, yyy, xxx, len, xmit);
  1337.  
  1338.    header[0] = '\020';
  1339.    header[4] = (unsigned char) (type << 3);
  1340.  
  1341.    switch (type) {
  1342.  
  1343.       case CLOSE:
  1344.          break;   /* stop protocol */
  1345.  
  1346.       case NAK:
  1347.          header[4] += (unsigned char) yyy;
  1348.          break;   /* reject */
  1349.  
  1350.       case SRJ:
  1351.          break;
  1352.  
  1353.       case ACK:
  1354.          header[4] += (unsigned char) yyy;
  1355.          break;   /* ack */
  1356.  
  1357.       case INITA:
  1358.       case INITC:
  1359.          header[4] += (unsigned char) xmit;
  1360.          break;
  1361.  
  1362.       case INITB:
  1363.          i = MINPKT;
  1364.          while( i < xmit )
  1365.          {
  1366.             header[4] ++;
  1367.             i *= 2;
  1368.          }
  1369.          break;
  1370.  
  1371.       case DATA:
  1372.          header[4] = (unsigned char) (0x80 + (xxx << 3) + yyy);
  1373.          if (len < xmit)              /* Short packet?              */
  1374.             header[4] |= 0x40;/* Count byte handled at higher level */
  1375.  
  1376. #ifdef UDEBUG
  1377.             printmsg(7, "data=|%.*s|", len, data);
  1378. #endif
  1379.          break;
  1380.  
  1381.       default:
  1382.          printmsg(0,"gspack: Invalid packet type %d",type);
  1383.          panic();
  1384.    } /* switch */
  1385.  
  1386. /*--------------------------------------------------------------------*/
  1387. /*    Now we finish up the header.  For data packets, determine       */
  1388. /*    the K number in header[1], which specifies the number of        */
  1389. /*    actual data bytes transmitted as a power of 2; we also          */
  1390. /*    compute a checksum on the data.                                 */
  1391. /*--------------------------------------------------------------------*/
  1392.  
  1393.    if (type == DATA)
  1394.    {
  1395.       header[1] = 1;
  1396.       i = MINPKT;
  1397.       while( i < xmit )
  1398.       {
  1399.          header[1] ++;
  1400.          i *= 2;
  1401.       }
  1402.  
  1403.       if ( i != xmit )        /* Did it come out exact power of 2?   */
  1404.       {
  1405.          printmsg(0,"Packet length error ... %d != %d for K = %d",
  1406.                i, xmit, (int) header[1]);
  1407.          panic();             /* No --> Well, we blew THAT math      */
  1408.       } /* if ( i != xmit ) */
  1409.  
  1410. /*--------------------------------------------------------------------*/
  1411. /*                        Compute the checksum                        */
  1412. /*--------------------------------------------------------------------*/
  1413.  
  1414.       check = checksum(data, xmit);
  1415.       i = header[4] & 0xff; /* got to do this on PC for ex-or high bits */
  1416.       check = (0xaaaa - ((check ^ i) & 0xffff)) & 0xffff;
  1417.    }
  1418.    else {
  1419.       header[1] = 9;          /* Control packet size K number (9)    */
  1420.       check = (0xaaaa - header[4]) & 0xffff;
  1421.                               /* Simple checksum for control         */
  1422.    } /* else */
  1423.  
  1424.    header[2] = (unsigned char) (check & 0xff);
  1425.    header[3] = (unsigned char) ((check >> 8) & 0xff);
  1426.    header[5] = (unsigned char)
  1427.             ((header[1] ^ header[2] ^ header[3] ^ header[4]) & 0xff) ;
  1428.  
  1429. #ifdef   LINKTEST
  1430.    /***** More Link Testing Mods *****/
  1431.    switch(dpkerr[0]) {
  1432.    case 'e':
  1433.       data[10] = - data[10];
  1434.       break;
  1435.    case 'h':
  1436.       header[5] = - header[5];
  1437.       break;
  1438.    case 'l':
  1439.       return;
  1440.    case 'p':
  1441.       swrite((char *) header, HDRSIZE);
  1442.       if (header[1] != 9)
  1443.          swrite(data, xmit - 3);
  1444.       return;
  1445.    default:
  1446.       break;
  1447.    }
  1448.    /***** End Link Testing Mods *****/
  1449. #endif   /* LINKTEST */
  1450.  
  1451.    swrite((char *) header, HDRSIZE);      /* header is 6-bytes long */
  1452.    if (header[1] != 9)
  1453.       swrite(data, xmit);
  1454.  
  1455. } /*gspack*/
  1456.  
  1457. /*
  1458.    g r p a c k
  1459.  
  1460.    Read packet
  1461.  
  1462.    on return: yyy=pkrec xxx=pksent len=length<=PKTSIZE  data=*data
  1463.  
  1464.    ret(type)       ok
  1465.    ret(DCP_EMPTY)  input buf empty
  1466.    ret(DCP_ERROR)  bad header
  1467.  
  1468.    ret(DCP_EMPTY)  lost packet timeout
  1469.    ret(DCP_ERROR)  checksum error
  1470.  
  1471.    NOTE (specifications for sread()):
  1472.  
  1473.    sread(buf, n, timeout)
  1474.       while(TRUE) {
  1475.          if (# of chars available >= n) (without dec internal counter)
  1476.             read n chars into buf (decrement internal char counter)
  1477.             break
  1478.     else
  1479.        if (time > timeout)
  1480.           break;
  1481.       }
  1482.       return(# of chars available)
  1483.  
  1484. */
  1485.  
  1486. static short grpack(unsigned *yyy,
  1487.                     unsigned *xxx,
  1488.                     unsigned *len,
  1489.                     char UUFAR *data,
  1490.                     const short timeout)
  1491. {
  1492.    static short got_hdr  = FALSE;
  1493.    static int received = 0;       /* Bytes already read into buffer */
  1494.    int needed;
  1495.  
  1496.    unsigned short type;
  1497.    unsigned check, checkchk;
  1498.    unsigned char i;
  1499.    unsigned total = 0;
  1500.    unsigned char c, c2;
  1501.  
  1502.    time_t start;
  1503.  
  1504.    if (got_hdr)
  1505.       goto get_data;
  1506.  
  1507. /*--------------------------------------------------------------------*/
  1508. /*   Spin up to timeout waiting for a Control-P, our sync character   */
  1509. /*--------------------------------------------------------------------*/
  1510.  
  1511.    start = 0;
  1512.    while (!got_hdr)
  1513.    {
  1514.       unsigned char *psync;
  1515.  
  1516.       needed = HDRSIZE - received;
  1517.       if ( needed > 0 )       /* Have enough bytes for header?       */
  1518.       {                       /* No --> Read as much as we need      */
  1519.          short wait;
  1520.  
  1521.          if ( start == 0 )    /* First pass through data?            */
  1522.          {                    /* Yes --> Set timers up               */
  1523.             start = time(nil(time_t));
  1524.             wait = timeout;
  1525.          } /* if ( start == 0 ) */
  1526.          else {
  1527.             wait = (short) (timeout - (short) (time(NULL) - start));
  1528.  
  1529.             if (wait < 0)     /* Negative timeout?                   */
  1530.                wait = 0;      /* Make it no time out                 */
  1531.          } /* else */
  1532.  
  1533.          if (sread((char *) &grpkt[received], needed, wait ) <
  1534.              (unsigned short) needed )
  1535.                               /* Did we get the needed data?         */
  1536.             return DCP_EMPTY; /* No --> Return to caller             */
  1537.  
  1538.          received += needed;
  1539.       } /* if ( needed < received ) */
  1540.  
  1541. /*--------------------------------------------------------------------*/
  1542. /*            Search for sync character in newly read data            */
  1543. /*--------------------------------------------------------------------*/
  1544.  
  1545. #ifdef UDEBUG
  1546.       printmsg(10,"grpack: Have %d characters after reading %d",
  1547.                received, needed);
  1548. #endif
  1549.  
  1550.       psync = memchr( grpkt, '\020', received );
  1551.       if ( psync == NULL )    /* Did we find the sync character?     */
  1552.          received = 0;        /* No --> Reset to empty buffer        */
  1553.       else if ( psync != grpkt ) /* First character in buffer?       */
  1554.       {                       /* No --> Make it first character      */
  1555.          received -= psync - grpkt;
  1556.          shifts++;
  1557.          memmove( grpkt, psync, received );
  1558.                               /* Shift buffer over                   */
  1559.       } /* else */
  1560.  
  1561. /*--------------------------------------------------------------------*/
  1562. /*    If we have read an entire packet header, then perform a         */
  1563. /*    simple XOR checksum to determine if it is valid.  If we have    */
  1564. /*    a valid checksum, drop out of this search, else drop the        */
  1565. /*    sync character and restart the scan.                            */
  1566. /*--------------------------------------------------------------------*/
  1567.  
  1568.       if ( received >= HDRSIZE )
  1569.       {
  1570.          i = (unsigned char) ((grpkt[1] ^ grpkt[2] ^ grpkt[3] ^
  1571.                                grpkt[4] ^ grpkt[5]) & 0xff);
  1572.          printmsg(i ? 2 : 10, "prpkt %02x %02x %02x %02x %02x .. %02x ",
  1573.             grpkt[1], grpkt[2], grpkt[3], grpkt[4], grpkt[5], i);
  1574.  
  1575.          if (i == 0)          /* Good header?                        */
  1576.             got_hdr = TRUE;   /* Yes --> Drop out of loop            */
  1577.          else {               /* No  --> Flag it, continue loop      */
  1578.             badhdr++;
  1579.             printmsg(GDEBUG, "*** bad pkt header ***");
  1580.             memmove( grpkt, &grpkt[ 1 ], --received );
  1581.                               /* Begin scanning for sync character
  1582.                                  with next byte                      */
  1583.          } /* else */
  1584.       } /* if ( received > HDRSIZE ) */
  1585.    } /* while */
  1586.  
  1587. /*--------------------------------------------------------------------*/
  1588. /*                       Handle control packets                       */
  1589. /*--------------------------------------------------------------------*/
  1590.  
  1591.    if (grpkt[1] == 9)
  1592.    {
  1593.       if ( data != NULL )
  1594.          *data = '\0';
  1595.       *len = 0;
  1596.       c = grpkt[4];
  1597.       type = (unsigned short) (c >> 3);
  1598.       *yyy = c & 0x07;
  1599.       *xxx = 0;
  1600.       check = 0;
  1601.       checkchk = 0;
  1602.       got_hdr = FALSE;
  1603.    }
  1604.  
  1605. /*--------------------------------------------------------------------*/
  1606. /*                        Handle data packets                         */
  1607. /*--------------------------------------------------------------------*/
  1608.    else {
  1609. get_data:
  1610.       if ( data == NULL )
  1611.       {
  1612.          printmsg(0,"grpack: Unexpected data packet!");
  1613.          received = 0;
  1614.          return(DCP_ERROR);
  1615.       }
  1616.  
  1617. /*--------------------------------------------------------------------*/
  1618. /*             Compute the size of the data block desired             */
  1619. /*--------------------------------------------------------------------*/
  1620.  
  1621.       total = 16 << grpkt[1];
  1622.       if (total > r_pktsize)  /* Within the defined limits?          */
  1623.       {                       /* No --> Other system has bad header,
  1624.                                  or the header got corrupted         */
  1625.          printmsg(0,"grpack: Invalid packet size %d (%d)",
  1626.             total, (int) grpkt[1]);
  1627.          received = 0;
  1628.          got_hdr = FALSE;
  1629.          return(DCP_ERROR);
  1630.       }
  1631.  
  1632.       needed = total + HDRSIZE - received;
  1633.                                  /* Compute byte required to fill
  1634.                                     data buffer                      */
  1635.  
  1636. /*--------------------------------------------------------------------*/
  1637. /*     If we don't have enough data in the buffer, read some more     */
  1638. /*--------------------------------------------------------------------*/
  1639.  
  1640.       if ((needed > 0) &&
  1641.           (sread((char *) &grpkt[HDRSIZE+total-needed], needed, timeout) <
  1642.            (unsigned short)needed))
  1643.          return(DCP_EMPTY);
  1644.  
  1645.       got_hdr = FALSE;           /* Must re-process header next pass */
  1646.  
  1647. /*--------------------------------------------------------------------*/
  1648. /*              Break packet header into various values               */
  1649. /*--------------------------------------------------------------------*/
  1650.  
  1651.       type = 0;
  1652.       c2 = grpkt[4];
  1653.       c = (unsigned char) (c2 & 0x3f);
  1654.       *xxx = c >> 3;
  1655.       *yyy = c & 0x07;
  1656.       check = ((grpkt[3] & 0xff) << 8) | (grpkt[2] & 0xff);
  1657.       checkchk = checksum( (char *) grpkt + HDRSIZE , total);
  1658.       i = (unsigned char) ((grpkt[4] | 0x80) & 0xff);
  1659.       checkchk = (0xaaaa - (checkchk ^ i)) & 0xffff;
  1660.       if (checkchk != check)
  1661.       {
  1662.          printmsg(4, "*** checksum error ***");
  1663.          memmove( grpkt, grpkt + HDRSIZE, total );
  1664.                               /* Save data so we can scan for sync   */
  1665.          received = total;    /* Note the amount of the data in buf  */
  1666.          return(DCP_ERROR);   /* Return to caller with error         */
  1667.       }
  1668.  
  1669. /*--------------------------------------------------------------------*/
  1670. /*    The checksum is correct, now determine the length of the        */
  1671. /*    data to return.                                                 */
  1672. /*--------------------------------------------------------------------*/
  1673.  
  1674.       *len = total;
  1675.  
  1676.       if (c2 & 0x40)
  1677.       {
  1678.          unsigned ii;
  1679.          if ( grpkt[HDRSIZE] & 0x80 )
  1680.          {
  1681.             ii = (grpkt[HDRSIZE] & 0x7f) + ((grpkt[HDRSIZE+1] & 0xff) << 7);
  1682.             *len -= ii;
  1683.             MEMCPY(data, grpkt + HDRSIZE + 2, *len);
  1684.          }
  1685.          else {
  1686.             ii = (grpkt[HDRSIZE] & 0xff);
  1687.             *len -= ii;
  1688.             MEMCPY(data, grpkt + HDRSIZE + 1, *len);
  1689.          } /* else */
  1690.       }
  1691.       else
  1692.          MEMCPY( data, grpkt + HDRSIZE, *len);
  1693.    } /* else */
  1694.  
  1695. /*--------------------------------------------------------------------*/
  1696. /*           Announce what we got and return to the caller            */
  1697. /*--------------------------------------------------------------------*/
  1698.  
  1699.    received = 0;              /* Returning entire buffer, reset count */
  1700.    printmsg(5, "receive packet type %d, yyy=%d, xxx=%d, len=%d",
  1701.       type, *yyy, *xxx, *len);
  1702.  
  1703. #ifdef UDEBUG
  1704.    printmsg(13, " checksum rec=%04x comp=%04x\ndata=|%.*s|",
  1705.       check, checkchk, total, grpkt + HDRSIZE);
  1706. #endif
  1707.  
  1708.    return(type);
  1709.  
  1710. } /*grpack*/
  1711.  
  1712. /*
  1713.    c h e c k s u m
  1714. */
  1715.  
  1716. static unsigned checksum(char *data, unsigned len)
  1717. {
  1718.    unsigned i, j;
  1719.    unsigned tmp, chk1, chk2;
  1720.    chk1 = 0xffff;
  1721.    chk2 = 0;
  1722.    j = len;
  1723.    for (i = 0; i < len; i++) {
  1724.       if (chk1 & 0x8000) {
  1725.          chk1 <<= 1;
  1726.          chk1++;
  1727.       } else {
  1728.          chk1 <<= 1;
  1729.       }
  1730.       tmp = chk1;
  1731.       chk1 += (data[i] & 0xff);
  1732.       chk2 += chk1 ^ j;
  1733.       if ((chk1 & 0xffff) <= (tmp & 0xffff))
  1734.          chk1 ^= chk2;
  1735.       j--;
  1736.    }
  1737.    return(chk1 & 0xffff);
  1738.  
  1739. } /*checksum*/
  1740.