Annotation of coherent/g/usr/lib/uucp/tay104/proti.c, revision 1.1.1.1

1.1       root        1: /* proti.c
                      2:    The 'i' protocol.
                      3: 
                      4:    Copyright (C) 1992 Ian Lance Taylor
                      5: 
                      6:    This file is part of the Taylor UUCP package.
                      7: 
                      8:    This program is free software; you can redistribute it and/or
                      9:    modify it under the terms of the GNU General Public License as
                     10:    published by the Free Software Foundation; either version 2 of the
                     11:    License, or (at your option) any later version.
                     12: 
                     13:    This program is distributed in the hope that it will be useful, but
                     14:    WITHOUT ANY WARRANTY; without even the implied warranty of
                     15:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                     16:    General Public License for more details.
                     17: 
                     18:    You should have received a copy of the GNU General Public License
                     19:    along with this program; if not, write to the Free Software
                     20:    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                     21: 
                     22:    The author of the program may be contacted at [email protected] or
                     23:    c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
                     24:    */
                     25: 
                     26: #include "uucp.h"
                     27: 
                     28: #if USE_RCS_ID
                     29: const char proti_rcsid[] = "$Id: proti.c,v 1.1 93/07/30 07:53:28 bin Exp Locker: bin $";
                     30: #endif
                     31: 
                     32: #include <ctype.h>
                     33: #include <errno.h>
                     34: 
                     35: #include "uudefs.h"
                     36: #include "uuconf.h"
                     37: #include "conn.h"
                     38: #include "trans.h"
                     39: #include "system.h"
                     40: #include "prot.h"
                     41: 
                     42: /* The 'i' protocol is a simple sliding window protocol, created by
                     43:    me.  It is in many ways similar to the 'g' protocol.  Several ideas
                     44:    are also taken from the paper ``A High-Throughput Message Transport
                     45:    System'' by P. Lauder.  I don't know where the paper was published,
                     46:    but the author's e-mail address is [email protected].  However, I
                     47:    haven't adopted his main idea, which is to dispense with windows
                     48:    entirely.  This is because some links still do require flow control
                     49:    and, more importantly, because I want to have a limit to the amount
                     50:    of data I must be able to resend upon request.  To reduce the costs
                     51:    of window acknowledgements, I use a large window and only require
                     52:    an ack at the halfway point.
                     53: 
                     54:    Each packet starts with a header containing the following
                     55:    information:
                     56: 
                     57:    Intro byte           8 bits          byte 1
                     58:    Packet number        5 bits          byte 2
                     59:    Local channel        3 bits
                     60:    Packet ack           5 bits          byte 3
                     61:    Remote channel       3 bits
                     62:    Packet type          3 bits          bytes 4-5
                     63:    Direction            1 bit
                     64:    Data length         12 bits
                     65:    Header check         8 bits          byte 6
                     66: 
                     67:    If the data length is not 0, this is followed by the data and a 32
                     68:    bit CRC checksum.
                     69: 
                     70:    The following packet types are defined:
                     71: 
                     72:    SYNC  Initialize the connection
                     73:    DATA  Data packet
                     74:    ACK   Simple acknowledgement with no data
                     75:    NAK   Negative acknowledgement; requests resend of single packet
                     76:    SPOS  Set file position
                     77:    CLOSE Close the connection
                     78:    */
                     79: 
                     80: /* The offsets of the bytes in the packet header.  */
                     81: 
                     82: #define IHDR_INTRO (0)
                     83: #define IHDR_LOCAL (1)
                     84: #define IHDR_REMOTE (2)
                     85: #define IHDR_CONTENTS1 (3)
                     86: #define IHDR_CONTENTS2 (4)
                     87: #define IHDR_CHECK (5)
                     88: 
                     89: /* Macros to set and extract values of IHDR_LOCAL and IHDR_REMOTE.  */
                     90: #define IHDRWIN_SET(iseq, ichan) (((iseq) << 3) | (ichan))
                     91: #define IHDRWIN_GETSEQ(ival) (((ival) >> 3) & 0x1f)
                     92: #define IHDRWIN_GETCHAN(ival) ((ival) & 0x07)
                     93: 
                     94: /* Macros to set and extract values of IHDR_CONTENTS fields.  */
                     95: #define IHDRCON_SET1(ttype, fcaller, cbytes) \
                     96:   (((ttype) << 5) | ((fcaller) ? (1 << 4) : 0) | (((cbytes) >> 8) & 0x0f))
                     97: #define IHDRCON_SET2(ttype, fcaller, cbytes) ((cbytes) & 0xff)
                     98: #define THDRCON_GETTYPE(i1, i2) (((i1) >> 5) & 0x07)
                     99: #define FHDRCON_GETCALLER(i1, i2) (((i1) & (1 << 4)) != 0)
                    100: #define CHDRCON_GETBYTES(i1, i2) ((((i1) & 0x0f) << 8) | ((i2) & 0xff))
                    101: 
                    102: /* Macros for the IHDR_CHECK field.  */
                    103: #define IHDRCHECK_VAL(zhdr) \
                    104:   ((zhdr[IHDR_LOCAL] \
                    105:     ^ zhdr[IHDR_REMOTE] \
                    106:     ^ zhdr[IHDR_CONTENTS1] \
                    107:     ^ zhdr[IHDR_CONTENTS2]) \
                    108:    & 0xff)
                    109: 
                    110: /* Length of the packet header.  */
                    111: #define CHDRLEN (6)
                    112: 
                    113: /* Amount of space to skip between start of packet and actual data.
                    114:    This is used to make the actual data longword aligned, to encourage
                    115:    good performance when copying data into the buffer.  */
                    116: #define CHDRSKIPLEN (CHDRLEN + (sizeof (long) - CHDRLEN % sizeof (long)))
                    117: 
                    118: /* Amount of space to skip between memory buffer and header.  */
                    119: #define CHDROFFSET (CHDRSKIPLEN - CHDRLEN)
                    120: 
                    121: /* Length of the trailing checksum.  */
                    122: #define CCKSUMLEN (4)
                    123: 
                    124: /* Macros to set and get the checksum.  These multiply evaluate their
                    125:    arguments.  */
                    126: #define ICKSUM_GET(z) \
                    127:   ((((((((unsigned long) ((z)[0] & 0xff)) << 8) \
                    128:        | (unsigned long) ((z)[1] & 0xff)) << 8) \
                    129:      | (unsigned long) ((z)[2] & 0xff)) << 8) \
                    130:    | (unsigned long) ((z)[3] & 0xff))
                    131: #define UCKSUM_SET(z, i) \
                    132:   (void) ((z)[0] = (((i) >> 24) & 0xff), \
                    133:          (z)[1] = (((i) >> 16) & 0xff), \
                    134:          (z)[2] = (((i) >> 8) & 0xff), \
                    135:          (z)[3] = ((i) & 0xff))
                    136: 
                    137: /* The header introduction character.  */
                    138: #define IINTRO ('\007')
                    139: 
                    140: /* The packet types.  */
                    141: 
                    142: #define DATA (0)
                    143: #define SYNC (1)
                    144: #define ACK (2)
                    145: #define NAK (3)
                    146: #define SPOS (4)
                    147: #define CLOSE (5)
                    148: 
                    149: /* Largest possible packet size (plus 1).  */
                    150: #define IMAXPACKSIZE (1 << 12)
                    151: 
                    152: /* Largest possible sequence number (plus 1).  */
                    153: #define IMAXSEQ 32
                    154: 
                    155: /* Get the next sequence number given a sequence number.  */
                    156: #define INEXTSEQ(i) ((i + 1) & (IMAXSEQ - 1))
                    157: 
                    158: /* Compute i1 - i2 in sequence space (i.e., the number of packets from
                    159:    i2 to i1).  */
                    160: #define CSEQDIFF(i1, i2) (((i1) + IMAXSEQ - (i2)) & (IMAXSEQ - 1))
                    161: 
                    162: /* Largest possible channel number (plus 1).  */
                    163: #define IMAXICHAN (8)
                    164: 
                    165: /* Default packet size to request (protocol parameter
                    166:    ``packet-size'').  */
                    167: #define IREQUEST_PACKSIZE (1024)
                    168: 
                    169: /* Default window size to request (protocol parameter ``window'').  */
                    170: #define IREQUEST_WINSIZE (16)
                    171: 
                    172: /* Default timeout to use when sending the SYNC packet (protocol
                    173:    parameter ``sync-timeout'').  */
                    174: #define CSYNC_TIMEOUT (10)
                    175: 
                    176: /* Default number of times to retry sending the SYNC packet (protocol
                    177:    parameter ``sync-retries'').  */
                    178: #define CSYNC_RETRIES (6)
                    179: 
                    180: /* Default timeout to use when waiting for a packet (protocol
                    181:    parameter ``timeout'').  */
                    182: #define CTIMEOUT (10)
                    183: 
                    184: /* Default number of times to retry sending a packet before giving up
                    185:    (protocol parameter ``retries'').  */
                    186: #define CRETRIES (6)
                    187: 
                    188: /* Default maximum level of errors to accept before giving up
                    189:    (protocol parameter ``errors'').  */
                    190: #define CERRORS (100)
                    191: 
                    192: /* Default decay rate.  Each time we receive this many packets
                    193:    succesfully, we decrement the error level by one (protocol
                    194:    parameter ``error-decay'').  */
                    195: #define CERROR_DECAY (10)
                    196: 
                    197: /* The default list of characters to avoid: XON and XOFF.  This string
                    198:    is processed as an escape sequence.  This is 'j' protocol parameter
                    199:    ``avoid''; it is defined in this file because the 'i' and 'j'
                    200:    protocols share protocol parameters.  */
                    201: #define ZAVOID "\\021\\023"
                    202: 
                    203: /* Local variables.  */
                    204: 
                    205: /* Packet size to request (protocol parameter ``packet-size'').  */
                    206: static int iIrequest_packsize = IREQUEST_PACKSIZE;
                    207: 
                    208: /* Window size to request (protocol parameter ``window'').  */
                    209: static int iIrequest_winsize = IREQUEST_WINSIZE;
                    210: 
                    211: /* Remote packet size (set from SYNC packet or from
                    212:    iIforced_remote_packsize).  */
                    213: static int iIremote_packsize;
                    214: 
                    215: /* Size which buffers were allocated for.  */
                    216: static int iIalc_packsize;
                    217: 
                    218: /* Forced remote packet size, used if non-zero (protocol parameter
                    219:    ``remote-packet-size'').  */
                    220: static int iIforced_remote_packsize = 0;
                    221: 
                    222: /* Remote window size (set from SYNC packet or from
                    223:    iIforced_remote_winsize).  */
                    224: static int iIremote_winsize;
                    225: 
                    226: /* Forced remote window size, used if non-zero (protocol parameter
                    227:    ``remote-window'').  */
                    228: static int iIforced_remote_winsize = 0;
                    229: 
                    230: /* Timeout to use when sending the SYNC packet (protocol
                    231:    parameter ``sync-timeout'').  */
                    232: int cIsync_timeout = CSYNC_TIMEOUT;
                    233: 
                    234: /* Number of times to retry sending the SYNC packet (protocol
                    235:    parameter ``sync-retries'').  */
                    236: static int cIsync_retries = CSYNC_RETRIES;
                    237: 
                    238: /* Timeout to use when waiting for a packet (protocol parameter
                    239:    ``timeout'').  */
                    240: static int cItimeout = CTIMEOUT;
                    241: 
                    242: /* Number of times to retry sending a packet before giving up
                    243:    (protocol parameter ``retries'').  */
                    244: static int cIretries = CRETRIES;
                    245: 
                    246: /* Maximum level of errors to accept before giving up (protocol
                    247:    parameter ``errors'').  */
                    248: static int cIerrors = CERRORS;
                    249: 
                    250: /* Each time we receive this many packets succesfully, we decrement
                    251:    the error level by one (protocol parameter ``error-decay'').  */
                    252: static int cIerror_decay = CERROR_DECAY;
                    253: 
                    254: /* The set of characters to avoid (protocol parameter ``avoid'').
                    255:    This is actually part of the 'j' protocol; it is defined in this
                    256:    file because the 'i' and 'j' protocols use the same protocol
                    257:    parameters.  */
                    258: const char *zJavoid_parameter = ZAVOID;
                    259: 
                    260: /* Routine to use when sending data.  This is a hook for the 'j'
                    261:    protocol.  */
                    262: static boolean (*pfIsend) P((struct sconnection *qconn, const char *zsend,
                    263:                             size_t csend, boolean fdoread));
                    264: 
                    265: /* Routine to use to use when reading data.  This is a hook for the
                    266:    'j' protocol.  */
                    267: static boolean (*pfIreceive) P((struct sconnection *qconn, size_t cneed,
                    268:                                size_t *pcrec, int ctimeout,
                    269:                                boolean freport));
                    270: 
                    271: /* Next sequence number to send.  */
                    272: static int iIsendseq;
                    273: 
                    274: /* Last sequence number received.  */
                    275: static int iIrecseq;
                    276: 
                    277: /* Last sequence number we have acknowledged.  */
                    278: static int iIlocal_ack;
                    279: 
                    280: /* Last sequence number remote system has acknowledged.  */
                    281: static int iIremote_ack;
                    282: 
                    283: /* File position we are sending from.  */
                    284: static long iIsendpos;
                    285: 
                    286: /* File position we are receiving to.  */
                    287: static long iIrecpos;
                    288: 
                    289: /* TRUE if closing the connection.  */
                    290: static boolean fIclosing;
                    291: 
                    292: /* Array of sent packets indexed by packet number.  */
                    293: static char *azIsendbuffers[IMAXSEQ];
                    294: 
                    295: /* Array of received packets that we aren't ready to process yet,
                    296:    indexed by packet number.  */
                    297: static char *azIrecbuffers[IMAXSEQ];
                    298: 
                    299: /* For each packet sequence number, record whether we sent a NAK for
                    300:    the packet.  */
                    301: static boolean afInaked[IMAXSEQ];
                    302: 
                    303: /* Number of SYNC packets received (used only to detect whether one
                    304:    was received).  */
                    305: static int cIsyncs;
                    306: 
                    307: /* Number of packets sent.  */
                    308: static long cIsent_packets;
                    309: 
                    310: /* Number of packets received.  */
                    311: static long cIreceived_packets;
                    312: 
                    313: /* Number of packets resent.  */
                    314: static long cIresent_packets;
                    315: 
                    316: /* Number of bad packet headers received.  */
                    317: static long cIbad_hdr;
                    318: 
                    319: /* Number of out of order packets received.  */
                    320: static long cIbad_order;
                    321: 
                    322: /* Number of bad checksums received.  */
                    323: static long cIbad_cksum;
                    324: 
                    325: /* Number of packets rejected by remote system.  */
                    326: static long cIremote_rejects;
                    327: 
                    328: /* Protocol parameter commands.  */
                    329: 
                    330: struct uuconf_cmdtab asIproto_params[] =
                    331: {
                    332:   { "packet-size", UUCONF_CMDTABTYPE_INT, (pointer) &iIrequest_packsize,
                    333:       NULL },
                    334:   { "window", UUCONF_CMDTABTYPE_INT, (pointer) &iIrequest_winsize, NULL },
                    335:   { "remote-packet-size", UUCONF_CMDTABTYPE_INT,
                    336:       (pointer) &iIforced_remote_packsize, NULL },
                    337:   { "remote-window", UUCONF_CMDTABTYPE_INT,
                    338:       (pointer) &iIforced_remote_winsize, NULL },
                    339:   { "sync-timeout", UUCONF_CMDTABTYPE_INT, (pointer) &cIsync_timeout,
                    340:       NULL },
                    341:   { "sync-retries", UUCONF_CMDTABTYPE_INT, (pointer) &cIsync_retries,
                    342:       NULL },
                    343:   { "timeout", UUCONF_CMDTABTYPE_INT, (pointer) &cItimeout, NULL },
                    344:   { "retries", UUCONF_CMDTABTYPE_INT, (pointer) &cIretries, NULL },
                    345:   { "errors", UUCONF_CMDTABTYPE_INT, (pointer) &cIerrors, NULL },
                    346:   { "error-decay", UUCONF_CMDTABTYPE_INT, (pointer) &cIerror_decay, NULL },
                    347:   /* The ``avoid'' protocol parameter is part of the 'j' protocol, but
                    348:      it is convenient for the 'i' and 'j' protocols to share the same
                    349:      protocol parameter table.  */
                    350:   { "avoid", UUCONF_CMDTABTYPE_STRING, (pointer) &zJavoid_parameter, NULL },
                    351:   { NULL, 0, NULL, NULL }
                    352: };
                    353: 
                    354: /* Local functions.  */
                    355: 
                    356: static boolean finak P((struct sdaemon *qdaemon, int iseq));
                    357: static boolean firesend P((struct sdaemon *qdaemon));
                    358: static boolean fiwindow_wait P((struct sdaemon *qdaemon));
                    359: static boolean fiwait_for_packet P((struct sdaemon *qdaemon,
                    360:                                    int ctimeout, int cretries,
                    361:                                    boolean fone, boolean *ftimedout));
                    362: static boolean ficheck_errors P((struct sdaemon *qdaemon));
                    363: static boolean fiprocess_data P((struct sdaemon *qdaemon,
                    364:                                 boolean *pfexit, boolean *pffound,
                    365:                                 size_t *pcneed));
                    366: static boolean fiprocess_packet P((struct sdaemon *qdaemon,
                    367:                                   const char *zhdr,
                    368:                                   const char *zfirst, int cfirst,
                    369:                                   const char *zsecond, int csecond,
                    370:                                   boolean *pfexit));
                    371: 
                    372: /* The 'i' protocol start routine.  The work is done in a routine
                    373:    which is also called by the 'j' protocol start routine.  */
                    374: 
                    375: boolean
                    376: fistart (qdaemon, pzlog)
                    377:      struct sdaemon *qdaemon;
                    378:      char **pzlog;
                    379: {
                    380:   return fijstart (qdaemon, pzlog, IMAXPACKSIZE, fsend_data, freceive_data);
                    381: }
                    382: 
                    383: /* Start the protocol.  This routine is called by both the 'i' and 'j'
                    384:    protocol start routines.  We keep transmitting a SYNC packet
                    385:    containing the window and packet size we would like to receive
                    386:    until we receive a SYNC packet from the remote system.  The first
                    387:    two bytes of the data contents of a SYNC packet are the maximum
                    388:    packet size we want to receive (high byte, low byte), and the next
                    389:    byte is the maximum window size we want to use.  */
                    390: 
                    391: boolean
                    392: fijstart (qdaemon, pzlog, imaxpacksize, pfsend, pfreceive)
                    393:      struct sdaemon *qdaemon;
                    394:      char **pzlog;
                    395:      int imaxpacksize;
                    396:      boolean (*pfsend) P((struct sconnection *qconn, const char *zsend,
                    397:                          size_t csend, boolean fdoread));
                    398:      boolean (*pfreceive) P((struct sconnection *qconn, size_t cneed,
                    399:                             size_t *pcrec, int ctimeout, boolean freport));
                    400: {
                    401:   char ab[CHDRLEN + 3 + CCKSUMLEN];
                    402:   unsigned long icksum;
                    403:   int ctries;
                    404:   int csyncs;
                    405: 
                    406:   *pzlog = NULL;
                    407: 
                    408:   pfIsend = pfsend;
                    409:   pfIreceive = pfreceive;
                    410: 
                    411:   if (iIforced_remote_packsize <= 0
                    412:       || iIforced_remote_packsize >= imaxpacksize)
                    413:     iIforced_remote_packsize = 0;
                    414:   else
                    415:     iIremote_packsize = iIforced_remote_packsize;
                    416:   iIalc_packsize = 0;
                    417:   if (iIforced_remote_winsize <= 0 || iIforced_remote_winsize >= IMAXSEQ)
                    418:     iIforced_remote_winsize = 0;
                    419:   else
                    420:     iIremote_winsize = iIforced_remote_winsize;
                    421: 
                    422:   iIsendseq = 1;
                    423:   iIrecseq = 0;
                    424:   iIlocal_ack = 0;
                    425:   iIremote_ack = 0;
                    426:   iIsendpos = 0;
                    427:   iIrecpos = 0;
                    428:   fIclosing = FALSE;
                    429: 
                    430:   cIsent_packets = 0;
                    431:   cIreceived_packets = 0;
                    432:   cIresent_packets = 0;
                    433:   cIbad_hdr = 0;
                    434:   cIbad_order = 0;
                    435:   cIbad_cksum = 0;
                    436:   cIremote_rejects = 0;
                    437: 
                    438:   ab[IHDR_INTRO] = IINTRO;
                    439:   ab[IHDR_LOCAL] = ab[IHDR_REMOTE] = IHDRWIN_SET (0, 0);
                    440:   ab[IHDR_CONTENTS1] = IHDRCON_SET1 (SYNC, qdaemon->fcaller, 3);
                    441:   ab[IHDR_CONTENTS2] = IHDRCON_SET2 (SYNC, qdaemon->fcaller, 3);
                    442:   ab[IHDR_CHECK] = IHDRCHECK_VAL (ab);
                    443:   ab[CHDRLEN + 0] = (iIrequest_packsize >> 8) & 0xff;
                    444:   ab[CHDRLEN + 1] = iIrequest_packsize & 0xff;
                    445:   ab[CHDRLEN + 2] = iIrequest_winsize;
                    446:   icksum = icrc (ab + CHDRLEN, 3, ICRCINIT);
                    447:   UCKSUM_SET (ab + CHDRLEN + 3, icksum);
                    448: 
                    449:   /* The static cIsyncs is incremented each time a SYNC packet is
                    450:      received.  */
                    451:   csyncs = cIsyncs;
                    452:   ctries = 0;
                    453: 
                    454:   while (TRUE)
                    455:     {
                    456:       boolean ftimedout;
                    457: 
                    458:       DEBUG_MESSAGE2 (DEBUG_PROTO,
                    459:                      "fistart: Sending SYNC packsize %d winsize %d",
                    460:                      iIrequest_packsize, iIrequest_winsize);
                    461: 
                    462:       if (! (*pfIsend) (qdaemon->qconn, ab, CHDRLEN + 3 + CCKSUMLEN,
                    463:                        TRUE))
                    464:        return FALSE;
                    465: 
                    466:       if (fiwait_for_packet (qdaemon, cIsync_timeout, 0, FALSE,
                    467:                             &ftimedout))
                    468:        {
                    469:          if (csyncs != cIsyncs)
                    470:            break;
                    471:        }
                    472:       else
                    473:        {
                    474:          if (! ftimedout)
                    475:            return FALSE;
                    476: 
                    477:          ++ctries;
                    478:          if (ctries > cIsync_retries)
                    479:            {
                    480:              ulog (LOG_ERROR, "Protocol startup failed");
                    481:              return FALSE;
                    482:            }
                    483:        }
                    484:     }
                    485: 
                    486:   /* We got a SYNC packet; set up packet buffers to use.  */
                    487:   if (iIremote_packsize > imaxpacksize)
                    488:     iIremote_packsize = imaxpacksize;
                    489:   do
                    490:     {
                    491:       int iseq;
                    492: 
                    493:       for (iseq = 0; iseq < IMAXSEQ; iseq++)
                    494:        {
                    495:          azIrecbuffers[iseq] = NULL;
                    496:          afInaked[iseq] = FALSE;
                    497:          azIsendbuffers[iseq] = (char *) malloc (iIremote_packsize
                    498:                                                  + CHDRSKIPLEN
                    499:                                                  + CCKSUMLEN);
                    500:          if (azIsendbuffers[iseq] == NULL)
                    501:            {
                    502:              int ifree;
                    503: 
                    504:              for (ifree = 0; ifree < iseq; ifree++)
                    505:                free ((pointer) azIsendbuffers[ifree]);
                    506:              break;
                    507:            }
                    508:        }
                    509: 
                    510:       if (iseq >= IMAXSEQ)
                    511:        {
                    512:          *pzlog = zbufalc (sizeof "protocol 'i' packet size %d window %d"
                    513:                            + 50);
                    514:          sprintf (*pzlog, "protocol '%c' packet size %d window %d",
                    515:                   qdaemon->qproto->bname, iIremote_packsize,
                    516:                   iIremote_winsize);
                    517:          iIalc_packsize = iIremote_packsize;
                    518: 
                    519:          return TRUE;
                    520:        }
                    521: 
                    522:       iIremote_packsize >>= 1;
                    523:     }
                    524:   while (iIremote_packsize > 200);
                    525: 
                    526:   ulog (LOG_ERROR,
                    527:        "'%c' protocol startup failed; insufficient memory for packets",
                    528:        qdaemon->qproto->bname);
                    529: 
                    530:   return FALSE;
                    531: }
                    532: 
                    533: /* Shut down the protocol.  We can be fairly informal about this,
                    534:    since we know that the upper level protocol has already exchanged
                    535:    hangup messages.  If we didn't know that, we would have to make
                    536:    sure that all packets before the CLOSE had been received.  */
                    537: 
                    538: boolean
                    539: fishutdown (qdaemon)
                    540:      struct sdaemon *qdaemon;
                    541: {
                    542:   char *z;
                    543:   size_t clen;
                    544: 
                    545:   fIclosing = TRUE;
                    546: 
                    547:   z = zigetspace (qdaemon, &clen) - CHDRLEN;
                    548: 
                    549:   z[IHDR_INTRO] = IINTRO;
                    550:   z[IHDR_LOCAL] = IHDRWIN_SET (iIsendseq, 0);
                    551:   z[IHDR_REMOTE] = IHDRWIN_SET (iIrecseq, 0);
                    552:   iIlocal_ack = iIrecseq;
                    553:   z[IHDR_CONTENTS1] = IHDRCON_SET1 (CLOSE, qdaemon->fcaller, 0);
                    554:   z[IHDR_CONTENTS2] = IHDRCON_SET2 (CLOSE, qdaemon->fcaller, 0);
                    555:   z[IHDR_CHECK] = IHDRCHECK_VAL (z);
                    556: 
                    557:   DEBUG_MESSAGE0 (DEBUG_PROTO, "fishutdown: Sending CLOSE");
                    558: 
                    559:   if (! (*pfIsend) (qdaemon->qconn, z, CHDRLEN, FALSE))
                    560:     return FALSE;
                    561: 
                    562:   ulog (LOG_NORMAL,
                    563:        "Protocol '%c' packets: sent %ld, resent %ld, received %ld",
                    564:        qdaemon->qproto->bname, cIsent_packets, cIresent_packets,
                    565:        cIreceived_packets);
                    566:   if (cIbad_hdr != 0
                    567:       || cIbad_cksum != 0
                    568:       || cIbad_order != 0
                    569:       || cIremote_rejects != 0)
                    570:     ulog (LOG_NORMAL,
                    571:          "Errors: header %ld, checksum %ld, order %ld, remote rejects %ld",
                    572:          cIbad_hdr, cIbad_cksum, cIbad_order, cIremote_rejects);
                    573: 
                    574:   /* Reset the protocol parameters to their default values.  */
                    575:   iIrequest_packsize = IREQUEST_PACKSIZE;
                    576:   iIrequest_winsize = IREQUEST_WINSIZE;
                    577:   iIforced_remote_packsize = 0;
                    578:   iIforced_remote_winsize = 0;
                    579:   cIsync_timeout = CSYNC_TIMEOUT;
                    580:   cIsync_retries = CSYNC_RETRIES;
                    581:   cItimeout = CTIMEOUT;
                    582:   cIretries = CRETRIES;
                    583:   cIerrors = CERRORS;
                    584:   cIerror_decay = CERROR_DECAY;
                    585:   zJavoid_parameter = ZAVOID;
                    586: 
                    587:   return TRUE;
                    588: }
                    589: 
                    590: /* Send a command string.  These are just sent as normal packets,
                    591:    ending in a packet containing a null byte.  */
                    592: 
                    593: boolean
                    594: fisendcmd (qdaemon, z, ilocal, iremote)
                    595:      struct sdaemon *qdaemon;
                    596:      const char *z;
                    597:      int ilocal;
                    598:      int iremote;
                    599: {
                    600:   size_t clen;
                    601: 
                    602:   DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO, "fisendcmd: Sending command \"%s\"", z);
                    603: 
                    604:   clen = strlen (z);
                    605: 
                    606:   while (TRUE)
                    607:     {
                    608:       char *zpacket;
                    609:       size_t csize;
                    610: 
                    611:       zpacket = zigetspace (qdaemon, &csize);
                    612: 
                    613:       if (clen < csize)
                    614:        {
                    615:          memcpy (zpacket, z, clen + 1);
                    616:          return fisenddata (qdaemon, zpacket, clen + 1, ilocal, iremote,
                    617:                             (long) -1);
                    618:        }
                    619: 
                    620:       memcpy (zpacket, z, csize);
                    621:       z += csize;
                    622:       clen -= csize;
                    623: 
                    624:       if (! fisenddata (qdaemon, zpacket, csize, ilocal, iremote, (long) -1))
                    625:        return FALSE;
                    626:     }
                    627:   /*NOTREACHED*/
                    628: }
                    629: 
                    630: /* Send a NAK.  */
                    631: 
                    632: static boolean
                    633: finak (qdaemon, iseq)
                    634:      struct sdaemon *qdaemon;
                    635:      int iseq;
                    636: {
                    637:   char abnak[CHDRLEN];
                    638: 
                    639:   abnak[IHDR_INTRO] = IINTRO;
                    640:   abnak[IHDR_LOCAL] = IHDRWIN_SET (iseq, 0);
                    641:   abnak[IHDR_REMOTE] = IHDRWIN_SET (iIrecseq, 0);
                    642:   iIlocal_ack = iIrecseq;
                    643:   abnak[IHDR_CONTENTS1] = IHDRCON_SET1 (NAK, qdaemon->fcaller, 0);
                    644:   abnak[IHDR_CONTENTS2] = IHDRCON_SET2 (NAK, qdaemon->fcaller, 0);
                    645:   abnak[IHDR_CHECK] = IHDRCHECK_VAL (abnak);
                    646: 
                    647:   afInaked[iseq] = TRUE;
                    648: 
                    649:   DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL,
                    650:                  "finak: Sending NAK %d", iseq);
                    651: 
                    652:   return (*pfIsend) (qdaemon->qconn, abnak, CHDRLEN, TRUE);
                    653: }
                    654: 
                    655: /* Resend the latest packet the remote has not acknowledged.  */
                    656: 
                    657: static boolean
                    658: firesend (qdaemon)
                    659:      struct sdaemon *qdaemon;
                    660: {
                    661:   int iseq;
                    662:   char *zhdr;
                    663:   size_t clen;
                    664: 
                    665:   iseq = INEXTSEQ (iIremote_ack);
                    666:   if (iseq == iIsendseq)
                    667:     {
                    668:       /* Everything has been ACKed and there is nothing to resend.  */
                    669:       return TRUE;
                    670:     }
                    671: 
                    672:   DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL,
                    673:                  "firesend: Resending packet %d", iseq);
                    674: 
                    675:   /* Update the received sequence number.  */
                    676:   zhdr = azIsendbuffers[iseq] + CHDROFFSET;
                    677:   if (IHDRWIN_GETSEQ (zhdr[IHDR_REMOTE]) != iIrecseq)
                    678:     {
                    679:       int iremote;
                    680: 
                    681:       iremote = IHDRWIN_GETCHAN (zhdr[IHDR_REMOTE]);
                    682:       zhdr[IHDR_REMOTE] = IHDRWIN_SET (iIrecseq, iremote);
                    683:       zhdr[IHDR_CHECK] = IHDRCHECK_VAL (zhdr);
                    684:       iIlocal_ack = iIrecseq;
                    685:     }
                    686: 
                    687:   ++cIresent_packets;
                    688: 
                    689:   clen = CHDRCON_GETBYTES (zhdr[IHDR_CONTENTS1],
                    690:                           zhdr[IHDR_CONTENTS2]);
                    691: 
                    692:   return (*pfIsend) (qdaemon->qconn, zhdr,
                    693:                     CHDRLEN + clen + (clen > 0 ? CCKSUMLEN : 0),
                    694:                     TRUE);
                    695: }
                    696: 
                    697: /* Wait until there is an opening in the receive window of the remote
                    698:    system.  */
                    699: 
                    700: static boolean
                    701: fiwindow_wait (qdaemon)
                    702:      struct sdaemon *qdaemon;
                    703: {
                    704:   /* iIsendseq is the sequence number we are sending, and iIremote_ack
                    705:      is the last sequence number acknowledged by the remote. */
                    706:   while (CSEQDIFF (iIsendseq, iIremote_ack) > iIremote_winsize)
                    707:     {
                    708:       /* If a NAK is lost, it is possible for the other side to be
                    709:         sending a stream of packets while we are waiting for an ACK.
                    710:         This should be caught in fiprocess_data; if it is about to
                    711:         send an ACK, but it has an unacknowledged packet to send, it
                    712:         sends the entire packet.  Hopefully that will trigger an ACK
                    713:         or a NAK and get us going again.  */
                    714:       DEBUG_MESSAGE0 (DEBUG_PROTO, "fiwindow_wait: Waiting for ACK");
                    715:       if (! fiwait_for_packet (qdaemon, cItimeout, cIretries,
                    716:                               TRUE, (boolean *) NULL))
                    717:        return FALSE;
                    718:     }
                    719: 
                    720:   return TRUE;
                    721: }
                    722: 
                    723: /* Get buffer space to use for packet data.  We return a pointer to
                    724:    the space to be used for the actual data, leaving room for the
                    725:    header.  */
                    726: 
                    727: /*ARGSUSED*/
                    728: char *
                    729: zigetspace (qdaemon, pclen)
                    730:      struct sdaemon *qdaemon;
                    731:      size_t *pclen;
                    732: {
                    733:   *pclen = iIremote_packsize;
                    734:   return azIsendbuffers[iIsendseq] + CHDRSKIPLEN;
                    735: }
                    736: 
                    737: /* Send a data packet.  The zdata argument will always point to value
                    738:    returned by zigetspace, so we know that we have room before it for
                    739:    the header information.  */
                    740: 
                    741: boolean
                    742: fisenddata (qdaemon, zdata, cdata, ilocal, iremote, ipos)
                    743:      struct sdaemon *qdaemon;
                    744:      char *zdata;
                    745:      size_t cdata;
                    746:      int ilocal;
                    747:      int iremote;
                    748:      long ipos;
                    749: {
                    750:   char *zhdr;
                    751:   unsigned long icksum;
                    752:   boolean fret;
                    753: 
                    754: #if DEBUG > 0
                    755:   if (ilocal < 0 || ilocal >= IMAXICHAN
                    756:       || iremote < 0 || iremote >= IMAXICHAN)
                    757:     ulog (LOG_FATAL, "fisenddata: ilocal %d iremote %d", ilocal, iremote);
                    758: #endif
                    759: 
                    760:   /* If we are changing the file position, we must send an SPOS
                    761:      packet.  */
                    762:   if (ipos != iIsendpos && ipos != (long) -1)
                    763:     {
                    764:       int inext;
                    765:       char *zspos;
                    766: 
                    767:       /* We need to get a buffer to hold the SPOS packet, and it needs
                    768:         to be next sequence number.  However, the data we have been
                    769:         given is currently in the next sequence number buffer.  So we
                    770:         shuffle the buffers around.  */
                    771:       inext = INEXTSEQ (iIsendseq);
                    772:       zspos = azIsendbuffers[inext];
                    773:       azIsendbuffers[inext] = zdata - CHDRSKIPLEN;
                    774:       azIsendbuffers[iIsendseq] = zspos;
                    775:       zspos += CHDROFFSET;
                    776: 
                    777:       zspos[IHDR_INTRO] = IINTRO;
                    778:       zspos[IHDR_LOCAL] = IHDRWIN_SET (iIsendseq, 0);
                    779:       zspos[IHDR_REMOTE] = IHDRWIN_SET (iIrecseq, 0);
                    780:       iIlocal_ack = iIrecseq;
                    781:       zspos[IHDR_CONTENTS1] = IHDRCON_SET1 (SPOS, qdaemon->fcaller,
                    782:                                            CCKSUMLEN);
                    783:       zspos[IHDR_CONTENTS2] = IHDRCON_SET2 (SPOS, qdaemon->fcaller,
                    784:                                            CCKSUMLEN);
                    785:       zspos[IHDR_CHECK] = IHDRCHECK_VAL (zspos);
                    786:       UCKSUM_SET (zspos + CHDRLEN, (unsigned long) ipos);
                    787:       icksum = icrc (zspos + CHDRLEN, CCKSUMLEN, ICRCINIT);
                    788:       UCKSUM_SET (zspos + CHDRLEN + CCKSUMLEN, icksum);
                    789: 
                    790:       /* Wait for an opening in the window.  */
                    791:       if (iIremote_winsize > 0
                    792:          && CSEQDIFF (iIsendseq, iIremote_ack) > iIremote_winsize)
                    793:        {
                    794:          if (! fiwindow_wait (qdaemon))
                    795:            return FALSE;
                    796:        }
                    797: 
                    798:       DEBUG_MESSAGE1 (DEBUG_PROTO, "fisenddata: Sending SPOS %ld",
                    799:                      ipos);
                    800: 
                    801:       if (! (*pfIsend) (qdaemon->qconn, zspos,
                    802:                        CHDRLEN + CCKSUMLEN + CCKSUMLEN, TRUE))
                    803:        return FALSE;
                    804: 
                    805:       iIsendseq = INEXTSEQ (iIsendseq);
                    806:       iIsendpos = ipos;
                    807:     }
                    808: 
                    809:   zhdr = zdata - CHDRLEN;
                    810:   zhdr[IHDR_INTRO] = IINTRO;
                    811:   zhdr[IHDR_LOCAL] = IHDRWIN_SET (iIsendseq, ilocal);
                    812:   zhdr[IHDR_CONTENTS1] = IHDRCON_SET1 (DATA, qdaemon->fcaller, cdata);
                    813:   zhdr[IHDR_CONTENTS2] = IHDRCON_SET2 (DATA, qdaemon->fcaller, cdata);
                    814: 
                    815:   /* Compute and set the checksum.  */
                    816:   if (cdata > 0)
                    817:     {
                    818:       icksum = icrc (zdata, cdata, ICRCINIT);
                    819:       UCKSUM_SET (zdata + cdata, icksum);
                    820:     }
                    821: 
                    822:   /* Wait until there is an opening in the window (we hope to not have
                    823:      to wait here at all, actually; ideally the window should be large
                    824:      enough to avoid a wait).  */
                    825:   if (iIremote_winsize > 0
                    826:       && CSEQDIFF (iIsendseq, iIremote_ack) > iIremote_winsize)
                    827:     {
                    828:       if (! fiwindow_wait (qdaemon))
                    829:        return FALSE;
                    830:     }
                    831: 
                    832:   /* We only fill in IHDR_REMOTE now, since only now do know the
                    833:      correct value of iIrecseq.  */
                    834:   zhdr[IHDR_REMOTE] = IHDRWIN_SET (iIrecseq, iremote);
                    835:   iIlocal_ack = iIrecseq;
                    836:   zhdr[IHDR_CHECK] = IHDRCHECK_VAL (zhdr);
                    837: 
                    838:   DEBUG_MESSAGE2 (DEBUG_PROTO, "fisenddata: Sending packet %d (%d bytes)",
                    839:                  iIsendseq, (int) cdata);
                    840: 
                    841:   iIsendseq = INEXTSEQ (iIsendseq);
                    842:   ++cIsent_packets;
                    843: 
                    844:   fret = (*pfIsend) (qdaemon->qconn, zhdr,
                    845:                     cdata + CHDRLEN + (cdata > 0 ? CCKSUMLEN : 0),
                    846:                     TRUE);
                    847: 
                    848:   iIsendpos += cdata;
                    849: 
                    850:   if (fret && iPrecstart != iPrecend)
                    851:     {
                    852:       boolean fexit;
                    853: 
                    854:       fret = fiprocess_data (qdaemon, &fexit, (boolean *) NULL,
                    855:                             (size_t *) NULL);
                    856:     }
                    857: 
                    858:   return fret;
                    859: }
                    860: 
                    861: /* Wait for data to come in.  */
                    862: 
                    863: boolean
                    864: fiwait (qdaemon)
                    865:      struct sdaemon *qdaemon;
                    866: {
                    867:   return fiwait_for_packet (qdaemon, cItimeout, cIretries,
                    868:                            FALSE, (boolean *) NULL);
                    869: }
                    870: 
                    871: /* Wait for a packet.  Either there is no data to send, or the remote
                    872:    window is full.  */
                    873: 
                    874: static boolean
                    875: fiwait_for_packet (qdaemon, ctimeout, cretries, fone, pftimedout)
                    876:      struct sdaemon *qdaemon;
                    877:      int ctimeout;
                    878:      int cretries;
                    879:      boolean fone;
                    880:      boolean *pftimedout;
                    881: {
                    882:   int cshort;
                    883:   int ctimeouts;
                    884: 
                    885:   if (pftimedout != NULL)
                    886:     *pftimedout = FALSE;
                    887: 
                    888:   cshort = 0;
                    889:   ctimeouts = 0;
                    890: 
                    891:   while (TRUE)
                    892:     {
                    893:       boolean fexit, ffound;
                    894:       size_t cneed;
                    895:       size_t crec;
                    896: 
                    897:       if (! fiprocess_data (qdaemon, &fexit, &ffound, &cneed))
                    898:        return FALSE;
                    899: 
                    900:       if (fexit || (fone && ffound))
                    901:        return TRUE;
                    902: 
                    903:       if (cneed == 0)
                    904:        continue;
                    905: 
                    906:       DEBUG_MESSAGE1 (DEBUG_PROTO, "fiwait_for_packet: Need %d bytes",
                    907:                      (int) cneed);
                    908: 
                    909:       if (! (*pfIreceive) (qdaemon->qconn, cneed, &crec, ctimeout, TRUE))
                    910:        return FALSE;
                    911: 
                    912:       if (crec != 0)
                    913:        {
                    914:          /* If we didn't get enough data twice in a row, we may have
                    915:             dropped some data and be waiting for the end of a large
                    916:             packet.  Incrementing iPrecstart will force
                    917:             fiprocess_data to skip the current packet and try to find
                    918:             the next one.  */
                    919:          if (crec >= cneed)
                    920:            cshort = 0;
                    921:          else
                    922:            {
                    923:              ++cshort;
                    924:              if (cshort > 1)
                    925:                {
                    926:                  iPrecstart = (iPrecstart + 1) % CRECBUFLEN;
                    927:                  cshort = 0;
                    928:                }
                    929:            }
                    930:        }
                    931:       else
                    932:        {
                    933:          int i;
                    934: 
                    935:          /* We timed out on the read.  */
                    936:          ++ctimeouts;
                    937:          if (ctimeouts > cretries)
                    938:            {
                    939:              if (cretries > 0)
                    940:                ulog (LOG_ERROR, "Timed out waiting for packet");
                    941:              if (pftimedout != NULL)
                    942:                *pftimedout = TRUE;
                    943:              return FALSE;
                    944:            }
                    945: 
                    946:          /* Clear out the list of packets we have sent NAKs for.  We
                    947:             should have seen some sort of response by now.  */
                    948:          for (i = 0; i < IMAXSEQ; i++)
                    949:            afInaked[i] = FALSE;
                    950: 
                    951:          /* Send a NAK for the packet we want, and, if we have an
                    952:             unacknowledged packet, send it again.  */
                    953:          if (! finak (qdaemon, INEXTSEQ (iIrecseq))
                    954:              || ! firesend (qdaemon))
                    955:            return FALSE;
                    956:        }
                    957:     }
                    958:   /*NOTREACHED*/
                    959: }
                    960: 
                    961: /* Make sure we haven't overflowed the permissible error level.  */
                    962: 
                    963: static boolean
                    964: ficheck_errors (qdaemon)
                    965:      struct sdaemon *qdaemon;
                    966: {
                    967:   if (cIerrors < 0)
                    968:     return TRUE;
                    969: 
                    970:   if (((cIbad_order + cIbad_hdr + cIbad_cksum + cIremote_rejects)
                    971:        - (cIreceived_packets / cIerror_decay))
                    972:       > cIerrors)
                    973:     {
                    974:       /* Try shrinking the packet size.  */
                    975:       if (iIrequest_packsize > 400)
                    976:        {
                    977:          char absync[CHDRLEN + 3 + CCKSUMLEN];
                    978:          unsigned long icksum;
                    979: 
                    980:          iIrequest_packsize /= 2;
                    981:          absync[IHDR_INTRO] = IINTRO;
                    982:          absync[IHDR_LOCAL] = IHDRWIN_SET (0, 0);
                    983:          absync[IHDR_REMOTE] = IHDRWIN_SET (iIrecseq, 0);
                    984:          iIlocal_ack = iIrecseq;
                    985:          absync[IHDR_CONTENTS1] = IHDRCON_SET1 (SYNC, qdaemon->fcaller, 3);
                    986:          absync[IHDR_CONTENTS2] = IHDRCON_SET2 (SYNC, qdaemon->fcaller, 3);
                    987:          absync[IHDR_CHECK] = IHDRCHECK_VAL (absync);
                    988:          absync[CHDRLEN + 0] = (iIrequest_packsize >> 8) & 0xff;
                    989:          absync[CHDRLEN + 1] = iIrequest_packsize & 0xff;
                    990:          absync[CHDRLEN + 2] = iIrequest_winsize;
                    991:          icksum = icrc (absync + CHDRLEN, 3, ICRCINIT);
                    992:          UCKSUM_SET (absync + CHDRLEN + 3, icksum);
                    993: 
                    994:          cIerrors *= 2;
                    995: 
                    996:          DEBUG_MESSAGE2 (DEBUG_PROTO | DEBUG_ABNORMAL,
                    997:                          "ficheck_errors: Sending SYNC packsize %d winsize %d",
                    998:                          iIrequest_packsize, iIrequest_winsize);
                    999: 
                   1000:          return (*pfIsend) (qdaemon->qconn, absync,
                   1001:                             CHDRLEN + 3 + CCKSUMLEN, TRUE);
                   1002:        }
                   1003: 
                   1004:       ulog (LOG_ERROR, "Too many '%c' protocol errors",
                   1005:            qdaemon->qproto->bname);
                   1006:       return FALSE;
                   1007:     }
                   1008: 
                   1009:   return TRUE;
                   1010: }
                   1011: 
                   1012: /* Process data waiting in the receive buffer, passing to the
                   1013:    fgot_data function.  */
                   1014: 
                   1015: static boolean
                   1016: fiprocess_data (qdaemon, pfexit, pffound, pcneed)
                   1017:      struct sdaemon *qdaemon;
                   1018:      boolean *pfexit;
                   1019:      boolean *pffound;
                   1020:      size_t *pcneed;
                   1021: {
                   1022:   boolean fbadhdr;
                   1023: 
                   1024:   if (pfexit != NULL)
                   1025:     *pfexit = FALSE;
                   1026:   if (pffound != NULL)
                   1027:     *pffound = FALSE;
                   1028: 
                   1029:   fbadhdr = FALSE;
                   1030: 
                   1031:   while (iPrecstart != iPrecend)
                   1032:     {
                   1033:       char ab[CHDRLEN];
                   1034:       int cfirst, csecond;
                   1035:       char *zfirst, *zsecond;
                   1036:       int i;
                   1037:       int iget;
                   1038:       int ttype;
                   1039:       int iseq;
                   1040:       int csize;
                   1041:       int iack;
                   1042: 
                   1043:       /* If we're closing the connection, ignore any data remaining in
                   1044:         the input buffer.  */
                   1045:       if (fIclosing)
                   1046:        {
                   1047:          if (pfexit != NULL)
                   1048:            *pfexit = TRUE;
                   1049:          if (pcneed != NULL)
                   1050:            *pcneed = 0;
                   1051:          return TRUE;
                   1052:        }
                   1053: 
                   1054:       /* Look for the IINTRO character.  */
                   1055:       if (abPrecbuf[iPrecstart] != IINTRO)
                   1056:        {
                   1057:          char *zintro;
                   1058:          int cintro;
                   1059: 
                   1060:          cintro = iPrecend - iPrecstart;
                   1061:          if (cintro < 0)
                   1062:            cintro = CRECBUFLEN - iPrecstart;
                   1063: 
                   1064:          zintro = memchr (abPrecbuf + iPrecstart, IINTRO, (size_t) cintro);
                   1065: 
                   1066:          if (zintro == NULL)
                   1067:            {
                   1068:              iPrecstart = (iPrecstart + cintro) % CRECBUFLEN;
                   1069:              continue;
                   1070:            }
                   1071: 
                   1072:          /* We don't need % CRECBUFLEN here because zintro - (abPrecbuf
                   1073:             + iPrecstart) < cintro <= CRECBUFLEN - iPrecstart.  */
                   1074:          iPrecstart += zintro - (abPrecbuf + iPrecstart);
                   1075:        }
                   1076: 
                   1077:       /* Get the header into ab.  */
                   1078:       for (i = 0, iget = iPrecstart;
                   1079:           i < CHDRLEN && iget != iPrecend;
                   1080:           i++, iget = (iget + 1) % CRECBUFLEN)
                   1081:        ab[i] = abPrecbuf[iget];
                   1082: 
                   1083:       if (i < CHDRLEN)
                   1084:        {
                   1085:          if (pcneed != NULL)
                   1086:            *pcneed = CHDRLEN - i;
                   1087:          return TRUE;
                   1088:        }
                   1089: 
                   1090:       if ((ab[IHDR_CHECK] & 0xff) != IHDRCHECK_VAL (ab)
                   1091:          || (FHDRCON_GETCALLER (ab[IHDR_CONTENTS1], ab[IHDR_CONTENTS2])
                   1092:              ? qdaemon->fcaller : ! qdaemon->fcaller))
                   1093:        {
                   1094:          /* We only report a single bad header message per call, to
                   1095:             avoid generating many errors if we get many INTRO bytes
                   1096:             in a row.  */
                   1097:          if (! fbadhdr)
                   1098:            {
                   1099:              DEBUG_MESSAGE0 (DEBUG_PROTO | DEBUG_ABNORMAL,
                   1100:                              "fiprocess_data: Bad header");
                   1101: 
                   1102:              ++cIbad_hdr;
                   1103:              if (! ficheck_errors (qdaemon))
                   1104:                return FALSE;
                   1105: 
                   1106:              fbadhdr = TRUE;
                   1107:            }
                   1108: 
                   1109:          iPrecstart = (iPrecstart + 1) % CRECBUFLEN;
                   1110:          continue;
                   1111:        }
                   1112: 
                   1113:       zfirst = zsecond = NULL;
                   1114:       cfirst = csecond = 0;
                   1115: 
                   1116:       ttype = THDRCON_GETTYPE (ab[IHDR_CONTENTS1], ab[IHDR_CONTENTS2]);
                   1117:       if (ttype == DATA || ttype == SPOS || ttype == CLOSE)
                   1118:        iseq = IHDRWIN_GETSEQ (ab[IHDR_LOCAL]);
                   1119:       else
                   1120:        iseq = -1;
                   1121:       csize = CHDRCON_GETBYTES (ab[IHDR_CONTENTS1], ab[IHDR_CONTENTS2]);
                   1122: 
                   1123:       if (iseq != -1)
                   1124:        {
                   1125:          /* Make sure this packet is in our receive window.  The last
                   1126:             packet we have acked is iIlocal_ack.  */
                   1127:          if (iIrequest_winsize > 0
                   1128:              && CSEQDIFF (iseq, iIlocal_ack) > iIrequest_winsize)
                   1129:            {
                   1130:              DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL,
                   1131:                              "fiprocess_data: Out of order packet %d",
                   1132:                              iseq);
                   1133: 
                   1134:              ++cIbad_order;
                   1135:              if (! ficheck_errors (qdaemon))
                   1136:                return FALSE;
                   1137: 
                   1138:              iPrecstart = (iPrecstart + 1) % CRECBUFLEN;
                   1139: 
                   1140:              continue;
                   1141:            }
                   1142:        }
                   1143: 
                   1144:       if (csize > 0)
                   1145:        {
                   1146:          int cinbuf;
                   1147:          char abcksum[CCKSUMLEN];
                   1148:          unsigned long ickdata;
                   1149: 
                   1150:          cinbuf = iPrecend - iPrecstart;
                   1151:          if (cinbuf < 0)
                   1152:            cinbuf += CRECBUFLEN;
                   1153:          if (cinbuf < CHDRLEN + csize + CCKSUMLEN)
                   1154:            {
                   1155:              if (pcneed != NULL)
                   1156:                *pcneed = CHDRLEN + csize + CCKSUMLEN - cinbuf;
                   1157:              return TRUE;
                   1158:            }
                   1159: 
                   1160:          if (iPrecend > iPrecstart)
                   1161:            {
                   1162:              cfirst = csize;
                   1163:              zfirst = abPrecbuf + iPrecstart + CHDRLEN;
                   1164:            }
                   1165:          else
                   1166:            {
                   1167:              cfirst = CRECBUFLEN - (iPrecstart + CHDRLEN);
                   1168:              if (cfirst <= 0)
                   1169:                {
                   1170:                  /* Here cfirst is non-positive, so subtracting from
                   1171:                     abPrecbuf will actually skip the appropriate number
                   1172:                     of bytes at the start of abPrecbuf.  */
                   1173:                  zfirst = abPrecbuf - cfirst;
                   1174:                  cfirst = csize;
                   1175:                }
                   1176:              else
                   1177:                {
                   1178:                  if (cfirst >= csize)
                   1179:                    cfirst = csize;
                   1180:                  else
                   1181:                    {
                   1182:                      zsecond = abPrecbuf;
                   1183:                      csecond = csize - cfirst;
                   1184:                    }
                   1185:                  zfirst = abPrecbuf + iPrecstart + CHDRLEN;
                   1186:                }
                   1187:            }
                   1188: 
                   1189:          /* Get the checksum into abcksum.  */
                   1190:          for (i = 0, iget = (iPrecstart + CHDRLEN + csize) % CRECBUFLEN;
                   1191:               i < CCKSUMLEN;
                   1192:               i++, iget = (iget + 1) % CRECBUFLEN)
                   1193:            abcksum[i] = abPrecbuf[iget];
                   1194: 
                   1195:          ickdata = icrc (zfirst, (size_t) cfirst, ICRCINIT);
                   1196:          if (csecond > 0)
                   1197:            ickdata = icrc (zsecond, (size_t) csecond, ickdata);
                   1198: 
                   1199:          if (ICKSUM_GET (abcksum) != ickdata)
                   1200:            {
                   1201:              DEBUG_MESSAGE2 (DEBUG_PROTO | DEBUG_ABNORMAL,
                   1202:                              "fiprocess_data: Bad checksum; data %lu, frame %lu",
                   1203:                              ickdata, ICKSUM_GET (abcksum));
                   1204: 
                   1205:              ++cIbad_cksum;
                   1206:              if (! ficheck_errors (qdaemon))
                   1207:                return FALSE;
                   1208: 
                   1209:              /* If this sequence number is in our receive window,
                   1210:                 send a NAK.  iIrecseq is the last sequence number we
                   1211:                 have succesfully received.  */
                   1212:              if (iseq != -1
                   1213:                  && iseq != iIrecseq
                   1214:                  && (iIrequest_winsize <= 0
                   1215:                      || CSEQDIFF (iseq, iIrecseq) <= iIrequest_winsize)
                   1216:                  && azIrecbuffers[iseq] == NULL)
                   1217:                {
                   1218:                  if (! finak (qdaemon, iseq))
                   1219:                    return FALSE;
                   1220:                }
                   1221: 
                   1222:              iPrecstart = (iPrecstart + 1) % CRECBUFLEN;
                   1223:              continue;
                   1224:            }
                   1225:        }
                   1226: 
                   1227:       /* Here we know that this is a valid packet, so we can adjust
                   1228:         iPrecstart accordingly.  */
                   1229:       if (csize == 0)
                   1230:        iPrecstart = (iPrecstart + CHDRLEN) % CRECBUFLEN;
                   1231:       else
                   1232:        {
                   1233:          iPrecstart = ((iPrecstart + CHDRLEN + csize + CCKSUMLEN)
                   1234:                        % CRECBUFLEN);
                   1235:          ++cIreceived_packets;
                   1236:        }
                   1237: 
                   1238:       /* Get the ack from the packet, if appropriate.  iIsendseq is
                   1239:         the next sequence number we are going to send, and
                   1240:         iIremote_ack is the last sequence number acknowledged by the
                   1241:         remote system.  */
                   1242:       iack = IHDRWIN_GETSEQ (ab[IHDR_REMOTE]);
                   1243:       if (iIremote_winsize > 0
                   1244:          && iack != iIsendseq
                   1245:          && CSEQDIFF (iack, iIremote_ack) <= iIremote_winsize
                   1246:          && CSEQDIFF (iIsendseq, iack) <= iIremote_winsize)
                   1247:        {
                   1248:          /* Call uwindow_acked each time packet 0 is acked.  */
                   1249:          if (iack < iIremote_ack)
                   1250:            uwindow_acked (qdaemon, FALSE);
                   1251:          iIremote_ack = iack;
                   1252:        }
                   1253: 
                   1254:       if (iseq != -1)
                   1255:        {
                   1256:          afInaked[iseq] = FALSE;
                   1257: 
                   1258:          /* If we haven't handled all previous packets, we must save
                   1259:             off this packet and deal with it later.  */
                   1260:          if (iseq != INEXTSEQ (iIrecseq))
                   1261:            {
                   1262:              if (iseq == iIrecseq
                   1263:                  || (iIrequest_winsize > 0
                   1264:                      && CSEQDIFF (iseq, iIrecseq) > iIrequest_winsize))
                   1265:                {
                   1266:                  DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL,
                   1267:                                  "fiprocess_data: Ignoring out of order packet %d",
                   1268:                                  iseq);
                   1269:                  continue;
                   1270:                }
                   1271:              else
                   1272:                {
                   1273:                  DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL,
                   1274:                                  "fiprocess_data: Saving unexpected packet %d",
                   1275:                                  iseq);
                   1276: 
                   1277:                  if (azIrecbuffers[iseq] == NULL)
                   1278:                    {
                   1279:                      azIrecbuffers[iseq] = zbufalc ((size_t) (CHDRLEN
                   1280:                                                               + csize));
                   1281:                      memcpy (azIrecbuffers[iseq], ab, CHDRLEN);
                   1282:                      if (csize > 0)
                   1283:                        {
                   1284:                          memcpy (azIrecbuffers[iseq] + CHDRLEN, zfirst,
                   1285:                                  (size_t) cfirst);
                   1286:                          if (csecond > 0)
                   1287:                            memcpy (azIrecbuffers[iseq] + CHDRLEN + cfirst,
                   1288:                                    zsecond, (size_t) csecond);
                   1289:                        }
                   1290:                    }
                   1291:                }
                   1292: 
                   1293:              /* Send NAK's for each packet between the last one we
                   1294:                 received and this one, avoiding any packets for which
                   1295:                 we've already sent NAK's or which we've already
                   1296:                 received.  */
                   1297:              for (i = INEXTSEQ (iIrecseq);
                   1298:                   i != iseq;
                   1299:                   i = INEXTSEQ (i))
                   1300:                {
                   1301:                  if (! afInaked[i]
                   1302:                      && azIrecbuffers[i] == NULL)
                   1303:                    {
                   1304:                      if (! finak (qdaemon, i))
                   1305:                        return FALSE;
                   1306:                    }
                   1307:                }
                   1308: 
                   1309:              continue;
                   1310:            }
                   1311: 
                   1312:          iIrecseq = iseq;
                   1313:        }
                   1314: 
                   1315:       if (pffound != NULL)
                   1316:        *pffound = TRUE;
                   1317: 
                   1318:       if (! fiprocess_packet (qdaemon, ab, zfirst, cfirst, zsecond, csecond,
                   1319:                              pfexit))
                   1320:        return FALSE;
                   1321: 
                   1322:       if (iseq != -1)
                   1323:        {
                   1324:          int inext;
                   1325: 
                   1326:          /* If we've already received the next packet(s), process
                   1327:             them.  */
                   1328:          inext = INEXTSEQ (iIrecseq);
                   1329:          while (azIrecbuffers[inext] != NULL)
                   1330:            {
                   1331:              char *z;
                   1332:              int c;
                   1333: 
                   1334:              z = azIrecbuffers[inext];
                   1335:              c = CHDRCON_GETBYTES (z[IHDR_CONTENTS1], z[IHDR_CONTENTS2]);
                   1336:              iIrecseq = inext;
                   1337:              if (! fiprocess_packet (qdaemon, z, z + CHDRLEN, c,
                   1338:                                      (char *) NULL, 0, pfexit))
                   1339:                return FALSE;
                   1340:              ubuffree (azIrecbuffers[inext]);
                   1341:              azIrecbuffers[inext] = NULL;
                   1342:              inext = INEXTSEQ (inext);
                   1343:            }
                   1344:        }
                   1345: 
                   1346:       /* If we have received half of our window size or more since the
                   1347:         last ACK, send one now.  Sending an ACK for half the window
                   1348:         at a time should significantly cut the acknowledgement
                   1349:         traffic when only one side is sending.  We should normally
                   1350:         not have to send an ACK if we have data to send, since each
                   1351:         packet sent will ACK the most recently received packet.
                   1352:         However, it can happen if we receive a burst of short
                   1353:         packets, such as a set of command acknowledgements.  */
                   1354:       if (iIrequest_winsize > 0
                   1355:          && CSEQDIFF (iIrecseq, iIlocal_ack) >= iIrequest_winsize / 2)
                   1356:        {
                   1357:          char aback[CHDRLEN];
                   1358: 
                   1359:          aback[IHDR_INTRO] = IINTRO;
                   1360:          aback[IHDR_LOCAL] = IHDRWIN_SET (0, 0);
                   1361:          aback[IHDR_REMOTE] = IHDRWIN_SET (iIrecseq, 0);
                   1362:          iIlocal_ack = iIrecseq;
                   1363:          aback[IHDR_CONTENTS1] = IHDRCON_SET1 (ACK, qdaemon->fcaller, 0);
                   1364:          aback[IHDR_CONTENTS2] = IHDRCON_SET2 (ACK, qdaemon->fcaller, 0);
                   1365:          aback[IHDR_CHECK] = IHDRCHECK_VAL (aback);
                   1366: 
                   1367:          DEBUG_MESSAGE1 (DEBUG_PROTO, "fiprocess_data: Sending ACK %d",
                   1368:                          iIrecseq);
                   1369: 
                   1370:          if (! (*pfIsend) (qdaemon->qconn, aback, CHDRLEN, TRUE))
                   1371:            return FALSE;
                   1372:        }
                   1373:     }
                   1374: 
                   1375:   if (pcneed != NULL)
                   1376:     *pcneed = CHDRLEN;
                   1377: 
                   1378:   return TRUE;
                   1379: }
                   1380: 
                   1381: /* Process a single packet.  */
                   1382: 
                   1383: static boolean
                   1384: fiprocess_packet (qdaemon, zhdr, zfirst, cfirst, zsecond, csecond, pfexit)
                   1385:      struct sdaemon *qdaemon;
                   1386:      const char *zhdr;
                   1387:      const char *zfirst;
                   1388:      int cfirst;
                   1389:      const char *zsecond;
                   1390:      int csecond;
                   1391:      boolean *pfexit;
                   1392: {
                   1393:   int ttype;
                   1394: 
                   1395:   ttype = THDRCON_GETTYPE (zhdr[IHDR_CONTENTS1], zhdr[IHDR_CONTENTS2]);
                   1396:   switch (ttype)
                   1397:     {
                   1398:     case DATA:
                   1399:       {
                   1400:        int iseq;
                   1401:        boolean fret;
                   1402: 
                   1403:        iseq = IHDRWIN_GETSEQ (zhdr[IHDR_LOCAL]);
                   1404:        DEBUG_MESSAGE2 (DEBUG_PROTO,
                   1405:                        "fiprocess_packet: Got DATA packet %d size %d",
                   1406:                        iseq, cfirst + csecond);
                   1407:        fret = fgot_data (qdaemon, zfirst, (size_t) cfirst,
                   1408:                          zsecond, (size_t) csecond,
                   1409:                          IHDRWIN_GETCHAN (zhdr[IHDR_REMOTE]),
                   1410:                          IHDRWIN_GETCHAN (zhdr[IHDR_LOCAL]),
                   1411:                          iIrecpos,
                   1412:                          INEXTSEQ (iIremote_ack) == iIsendseq,
                   1413:                          pfexit);
                   1414:        iIrecpos += cfirst + csecond;
                   1415:        return fret;
                   1416:       }
                   1417: 
                   1418:     case SYNC:
                   1419:       {
                   1420:        int ipack, iwin;
                   1421: 
                   1422:        /* We accept a SYNC packet to adjust the packet and window
                   1423:           sizes at any time.  */
                   1424:        if (cfirst + csecond < 3)
                   1425:          {
                   1426:            ulog (LOG_ERROR, "Bad SYNC packet");
                   1427:            return FALSE;
                   1428:          }
                   1429:        ipack = (zfirst[0] & 0xff) << 8;
                   1430:        if (cfirst > 1)
                   1431:          ipack |= zfirst[1] & 0xff;
                   1432:        else
                   1433:          ipack |= zsecond[0];
                   1434:        if (cfirst > 2)
                   1435:          iwin = zfirst[2];
                   1436:        else
                   1437:          iwin = zsecond[2 - cfirst];
                   1438: 
                   1439:        DEBUG_MESSAGE2 (DEBUG_PROTO,
                   1440:                        "fiprocess_packet: Got SYNC packsize %d winsize %d",
                   1441:                        ipack, iwin);
                   1442: 
                   1443:        if (iIforced_remote_packsize == 0
                   1444:            && (iIalc_packsize == 0
                   1445:                || ipack <= iIalc_packsize))
                   1446:          iIremote_packsize = ipack;
                   1447:        if (iIforced_remote_winsize == 0)
                   1448:          iIremote_winsize = iwin;
                   1449: 
                   1450:        /* We increment a static variable to tell the initialization
                   1451:           code that a SYNC was received, and we set *pfexit to TRUE
                   1452:           to get out to the initialization code (this will do no harm
                   1453:           if we are called from elsewhere).  */
                   1454:        ++cIsyncs;
                   1455:        *pfexit = TRUE;
                   1456:        return TRUE;
                   1457:       }
                   1458: 
                   1459:     case ACK:
                   1460:       /* There is nothing to do here, since the ack was already
                   1461:         handled in fiprocess_data.  */
                   1462:       DEBUG_MESSAGE1 (DEBUG_PROTO,
                   1463:                      "fiprocess_packet: Got ACK %d",
                   1464:                      IHDRWIN_GETSEQ (zhdr[IHDR_REMOTE]));
                   1465:       return TRUE;
                   1466: 
                   1467:     case NAK:
                   1468:       /* We must resend the requested packet.  */
                   1469:       {      
                   1470:        int iseq;
                   1471:        char *zsend;
                   1472:        size_t clen;
                   1473: 
                   1474:        ++cIremote_rejects;
                   1475:        if (! ficheck_errors (qdaemon))
                   1476:          return FALSE;
                   1477: 
                   1478:        iseq = IHDRWIN_GETSEQ (zhdr[IHDR_LOCAL]);
                   1479: 
                   1480:        /* The timeout code will send a NAK for the packet the remote
                   1481:           side wants.  So we may see a NAK here for the packet we are
                   1482:           about to send.  */
                   1483:        if (iseq == iIsendseq
                   1484:            || (iIremote_winsize > 0
                   1485:                && (CSEQDIFF (iseq, iIremote_ack) > iIremote_winsize
                   1486:                    || CSEQDIFF (iIsendseq, iseq) > iIremote_winsize)))
                   1487:          {
                   1488:            DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL,
                   1489:                            "fiprocess_packet: Ignoring out of order NAK %d",
                   1490:                            iseq);
                   1491:            return TRUE;
                   1492:          }
                   1493: 
                   1494:        DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL,
                   1495:                        "fiprocess_packet: Got NAK %d; resending packet",
                   1496:                        iseq);
                   1497: 
                   1498:        /* Update the received sequence number.  */
                   1499:        zsend = azIsendbuffers[iseq] + CHDROFFSET;
                   1500:        if (IHDRWIN_GETSEQ (zsend[IHDR_REMOTE]) != iIrecseq)
                   1501:          {
                   1502:            int iremote;
                   1503: 
                   1504:            iremote = IHDRWIN_GETCHAN (zsend[IHDR_REMOTE]);
                   1505:            zsend[IHDR_REMOTE] = IHDRWIN_SET (iIrecseq, iremote);
                   1506:            zsend[IHDR_CHECK] = IHDRCHECK_VAL (zsend);
                   1507:            iIlocal_ack = iIrecseq;
                   1508:          }
                   1509:              
                   1510:        ++cIresent_packets;
                   1511: 
                   1512:        clen = CHDRCON_GETBYTES (zsend[IHDR_CONTENTS1],
                   1513:                                 zsend[IHDR_CONTENTS2]);
                   1514: 
                   1515:        return (*pfIsend) (qdaemon->qconn, zsend,
                   1516:                           CHDRLEN + clen + (clen > 0 ? CCKSUMLEN : 0),
                   1517:                           TRUE);
                   1518:       }
                   1519: 
                   1520:     case SPOS:
                   1521:       /* Set the file position.  */
                   1522:       {
                   1523:        char abpos[CCKSUMLEN];
                   1524:        const char *zpos;
                   1525: 
                   1526:        if (cfirst >= CCKSUMLEN)
                   1527:          zpos = zfirst;
                   1528:        else
                   1529:          {
                   1530:            memcpy (abpos, zfirst, (size_t) cfirst);
                   1531:            memcpy (abpos + cfirst, zsecond, (size_t) (CCKSUMLEN - cfirst));
                   1532:            zpos = abpos;
                   1533:          }
                   1534:        iIrecpos = (long) ICKSUM_GET (zpos);
                   1535:        DEBUG_MESSAGE1 (DEBUG_PROTO,
                   1536:                        "fiprocess_packet: Got SPOS %ld", iIrecpos);
                   1537:        return TRUE;
                   1538:       }
                   1539: 
                   1540:     case CLOSE:
                   1541:       {
                   1542:        boolean fexpected;
                   1543: 
                   1544:        fexpected = ! fLog_sighup || fIclosing;
                   1545:        if (! fexpected)
                   1546:          ulog (LOG_ERROR, "Received unexpected CLOSE packet");
                   1547:        else
                   1548:          DEBUG_MESSAGE0 (DEBUG_PROTO, "fiprocess_packet: Got CLOSE packet");
                   1549: 
                   1550:        fIclosing = TRUE;
                   1551:        *pfexit = TRUE;
                   1552:        return fexpected;
                   1553:       }
                   1554: 
                   1555:     default:
                   1556:       /* Just ignore unrecognized packet types, for future protocol
                   1557:         enhancements.  */
                   1558:       DEBUG_MESSAGE1 (DEBUG_PROTO, "fiprocess_packet: Got packet type %d",
                   1559:                      ttype);
                   1560:       return TRUE;
                   1561:     }
                   1562:   /*NOTREACHED*/
                   1563: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.