Annotation of coherent/g/usr/lib/uucp/tay104/proti.c, revision 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.