diff options
Diffstat (limited to 'gnu/libexec/uucp/uucico/proti.c')
-rw-r--r-- | gnu/libexec/uucp/uucico/proti.c | 261 |
1 files changed, 177 insertions, 84 deletions
diff --git a/gnu/libexec/uucp/uucico/proti.c b/gnu/libexec/uucp/uucico/proti.c index d14d42b42db0..fd243de23731 100644 --- a/gnu/libexec/uucp/uucico/proti.c +++ b/gnu/libexec/uucp/uucico/proti.c @@ -1,7 +1,7 @@ /* proti.c The 'i' protocol. - Copyright (C) 1992 Ian Lance Taylor + Copyright (C) 1992, 1993 Ian Lance Taylor This file is part of the Taylor UUCP package. @@ -20,13 +20,13 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. The author of the program may be contacted at ian@airs.com or - c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. + c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139. */ #include "uucp.h" #if USE_RCS_ID -const char proti_rcsid[] = "$Id: proti.c,v 1.1 1993/08/05 18:27:12 conklin Exp $"; +const char proti_rcsid[] = "$Id: proti.c,v 1.2 1994/05/07 18:13:48 ache Exp $"; #endif #include <ctype.h> @@ -153,7 +153,10 @@ const char proti_rcsid[] = "$Id: proti.c,v 1.1 1993/08/05 18:27:12 conklin Exp $ #define IMAXSEQ 32 /* Get the next sequence number given a sequence number. */ -#define INEXTSEQ(i) ((i + 1) & (IMAXSEQ - 1)) +#define INEXTSEQ(i) (((i) + 1) & (IMAXSEQ - 1)) + +/* Get the previous sequence number given a sequence number. */ +#define IPREVSEQ(i) (((i) + IMAXSEQ - 1) & (IMAXSEQ - 1)) /* Compute i1 - i2 in sequence space (i.e., the number of packets from i2 to i1). */ @@ -216,17 +219,14 @@ static int iIremote_packsize; static int iIalc_packsize; /* Forced remote packet size, used if non-zero (protocol parameter - ``remote-packet-size''). */ + ``remote-packet-size''). There is no forced remote window size + because the ACK strategy requires that both sides agree on the + window size. */ static int iIforced_remote_packsize = 0; -/* Remote window size (set from SYNC packet or from - iIforced_remote_winsize). */ +/* Remote window size (set from SYNC packet). */ static int iIremote_winsize; -/* Forced remote window size, used if non-zero (protocol parameter - ``remote-window''). */ -static int iIforced_remote_winsize = 0; - /* Timeout to use when sending the SYNC packet (protocol parameter ``sync-timeout''). */ int cIsync_timeout = CSYNC_TIMEOUT; @@ -251,6 +251,11 @@ static int cIerrors = CERRORS; the error level by one (protocol parameter ``error-decay''). */ static int cIerror_decay = CERROR_DECAY; +/* The number of packets we should wait to receive before sending an + ACK; this is set by default to half the window size we have + requested (protocol parameter ``ack-frequency''). */ +static int cIack_frequency = 0; + /* The set of characters to avoid (protocol parameter ``avoid''). This is actually part of the 'j' protocol; it is defined in this file because the 'i' and 'j' protocols use the same protocol @@ -334,8 +339,6 @@ struct uuconf_cmdtab asIproto_params[] = { "window", UUCONF_CMDTABTYPE_INT, (pointer) &iIrequest_winsize, NULL }, { "remote-packet-size", UUCONF_CMDTABTYPE_INT, (pointer) &iIforced_remote_packsize, NULL }, - { "remote-window", UUCONF_CMDTABTYPE_INT, - (pointer) &iIforced_remote_winsize, NULL }, { "sync-timeout", UUCONF_CMDTABTYPE_INT, (pointer) &cIsync_timeout, NULL }, { "sync-retries", UUCONF_CMDTABTYPE_INT, (pointer) &cIsync_retries, @@ -344,6 +347,7 @@ struct uuconf_cmdtab asIproto_params[] = { "retries", UUCONF_CMDTABTYPE_INT, (pointer) &cIretries, NULL }, { "errors", UUCONF_CMDTABTYPE_INT, (pointer) &cIerrors, NULL }, { "error-decay", UUCONF_CMDTABTYPE_INT, (pointer) &cIerror_decay, NULL }, + { "ack-frequency", UUCONF_CMDTABTYPE_INT, (pointer) &cIack_frequency, NULL }, /* The ``avoid'' protocol parameter is part of the 'j' protocol, but it is convenient for the 'i' and 'j' protocols to share the same protocol parameter table. */ @@ -398,7 +402,7 @@ fijstart (qdaemon, pzlog, imaxpacksize, pfsend, pfreceive) boolean (*pfreceive) P((struct sconnection *qconn, size_t cneed, size_t *pcrec, int ctimeout, boolean freport)); { - char ab[CHDRLEN + 3 + CCKSUMLEN]; + char ab[CHDRLEN + 4 + CCKSUMLEN]; unsigned long icksum; int ctries; int csyncs; @@ -414,10 +418,6 @@ fijstart (qdaemon, pzlog, imaxpacksize, pfsend, pfreceive) else iIremote_packsize = iIforced_remote_packsize; iIalc_packsize = 0; - if (iIforced_remote_winsize <= 0 || iIforced_remote_winsize >= IMAXSEQ) - iIforced_remote_winsize = 0; - else - iIremote_winsize = iIforced_remote_winsize; iIsendseq = 1; iIrecseq = 0; @@ -435,16 +435,41 @@ fijstart (qdaemon, pzlog, imaxpacksize, pfsend, pfreceive) cIbad_cksum = 0; cIremote_rejects = 0; + if (iIrequest_packsize < 0 || iIrequest_packsize > imaxpacksize) + { + ulog (LOG_ERROR, "Illegal protocol '%c' packet size; using %d", + qdaemon->qproto->bname, imaxpacksize); + iIrequest_packsize = imaxpacksize; + } + + /* The maximum permissible window size is 16. Otherwise the + protocol can get confused because a duplicated packet may arrive + out of order. If the window size is large in such a case, the + duplicate packet may be treated as a packet in the upcoming + window, causing the protocol to assume that all intermediate + packets have been lost, leading to immense confusion. */ + if (iIrequest_winsize < 0 || iIrequest_winsize > IMAXSEQ / 2) + { + ulog (LOG_ERROR, "Illegal protocol '%c' window size; using %d", + qdaemon->qproto->bname, IREQUEST_WINSIZE); + iIrequest_winsize = IREQUEST_WINSIZE; + } + + /* The default for the ACK frequency is half the window size. */ + if (cIack_frequency <= 0 || cIack_frequency >= iIrequest_winsize) + cIack_frequency = iIrequest_winsize / 2; + ab[IHDR_INTRO] = IINTRO; ab[IHDR_LOCAL] = ab[IHDR_REMOTE] = IHDRWIN_SET (0, 0); - ab[IHDR_CONTENTS1] = IHDRCON_SET1 (SYNC, qdaemon->fcaller, 3); - ab[IHDR_CONTENTS2] = IHDRCON_SET2 (SYNC, qdaemon->fcaller, 3); + ab[IHDR_CONTENTS1] = IHDRCON_SET1 (SYNC, qdaemon->fcaller, 4); + ab[IHDR_CONTENTS2] = IHDRCON_SET2 (SYNC, qdaemon->fcaller, 4); ab[IHDR_CHECK] = IHDRCHECK_VAL (ab); ab[CHDRLEN + 0] = (iIrequest_packsize >> 8) & 0xff; ab[CHDRLEN + 1] = iIrequest_packsize & 0xff; ab[CHDRLEN + 2] = iIrequest_winsize; - icksum = icrc (ab + CHDRLEN, 3, ICRCINIT); - UCKSUM_SET (ab + CHDRLEN + 3, icksum); + ab[CHDRLEN + 3] = qdaemon->cchans; + icksum = icrc (ab + CHDRLEN, 4, ICRCINIT); + UCKSUM_SET (ab + CHDRLEN + 4, icksum); /* The static cIsyncs is incremented each time a SYNC packet is received. */ @@ -455,11 +480,11 @@ fijstart (qdaemon, pzlog, imaxpacksize, pfsend, pfreceive) { boolean ftimedout; - DEBUG_MESSAGE2 (DEBUG_PROTO, - "fistart: Sending SYNC packsize %d winsize %d", - iIrequest_packsize, iIrequest_winsize); + DEBUG_MESSAGE3 (DEBUG_PROTO, + "fistart: Sending SYNC packsize %d winsize %d channels %d", + iIrequest_packsize, iIrequest_winsize, qdaemon->cchans); - if (! (*pfIsend) (qdaemon->qconn, ab, CHDRLEN + 3 + CCKSUMLEN, + if (! (*pfIsend) (qdaemon->qconn, ab, CHDRLEN + 4 + CCKSUMLEN, TRUE)) return FALSE; @@ -509,11 +534,15 @@ fijstart (qdaemon, pzlog, imaxpacksize, pfsend, pfreceive) if (iseq >= IMAXSEQ) { - *pzlog = zbufalc (sizeof "protocol 'i' packet size %d window %d" - + 50); - sprintf (*pzlog, "protocol '%c' packet size %d window %d", - qdaemon->qproto->bname, iIremote_packsize, - iIremote_winsize); + *pzlog = + zbufalc (sizeof "protocol '' sending packet/window / receiving /" + + 64); + sprintf (*pzlog, + "protocol '%c' sending packet/window %d/%d receiving %d/%d", + qdaemon->qproto->bname, (int) iIremote_packsize, + (int) iIremote_winsize, (int) iIrequest_packsize, + (int) iIrequest_winsize); + iIalc_packsize = iIremote_packsize; return TRUE; @@ -575,13 +604,13 @@ fishutdown (qdaemon) iIrequest_packsize = IREQUEST_PACKSIZE; iIrequest_winsize = IREQUEST_WINSIZE; iIforced_remote_packsize = 0; - iIforced_remote_winsize = 0; cIsync_timeout = CSYNC_TIMEOUT; cIsync_retries = CSYNC_RETRIES; cItimeout = CTIMEOUT; cIretries = CRETRIES; cIerrors = CERRORS; cIerror_decay = CERROR_DECAY; + cIack_frequency = 0; zJavoid_parameter = ZAVOID; return TRUE; @@ -835,8 +864,9 @@ fisenddata (qdaemon, zdata, cdata, ilocal, iremote, ipos) iIlocal_ack = iIrecseq; zhdr[IHDR_CHECK] = IHDRCHECK_VAL (zhdr); - DEBUG_MESSAGE2 (DEBUG_PROTO, "fisenddata: Sending packet %d (%d bytes)", - iIsendseq, (int) cdata); + DEBUG_MESSAGE4 (DEBUG_PROTO, + "fisenddata: Sending packet %d size %d local %d remote %d", + iIsendseq, (int) cdata, ilocal, iremote); iIsendseq = INEXTSEQ (iIsendseq); ++cIsent_packets; @@ -977,6 +1007,8 @@ ficheck_errors (qdaemon) char absync[CHDRLEN + 3 + CCKSUMLEN]; unsigned long icksum; + /* Don't bother sending the number of channels in this + packet. */ iIrequest_packsize /= 2; absync[IHDR_INTRO] = IINTRO; absync[IHDR_LOCAL] = IHDRWIN_SET (0, 0); @@ -1127,9 +1159,9 @@ fiprocess_data (qdaemon, pfexit, pffound, pcneed) if (iIrequest_winsize > 0 && CSEQDIFF (iseq, iIlocal_ack) > iIrequest_winsize) { - DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL, - "fiprocess_data: Out of order packet %d", - iseq); + DEBUG_MESSAGE2 (DEBUG_PROTO | DEBUG_ABNORMAL, + "fiprocess_data: Out of order packet %d (ack %d)", + iseq, iIlocal_ack); ++cIbad_order; if (! ficheck_errors (qdaemon)) @@ -1253,7 +1285,27 @@ fiprocess_data (qdaemon, pfexit, pffound, pcneed) if (iseq != -1) { - afInaked[iseq] = FALSE; + /* If we already sent a NAK for this packet, and we have not + seen the previous packet, then forget that we sent a NAK + for this and any preceding packets. This is to handle + the following sequence: + receive packet 0 + packets 1 and 2 lost + receive packet 3 + send NAK 1 + send NAK 2 + packet 1 lost + receive packet 2 + At this point we want to send NAK 1. */ + if (afInaked[iseq] + && azIrecbuffers[IPREVSEQ (iseq)] == NULL) + { + for (i = INEXTSEQ (iIrecseq); + i != iseq; + i = INEXTSEQ (i)) + afInaked[i] = FALSE; + afInaked[iseq] = FALSE; + } /* If we haven't handled all previous packets, we must save off this packet and deal with it later. */ @@ -1263,16 +1315,16 @@ fiprocess_data (qdaemon, pfexit, pffound, pcneed) || (iIrequest_winsize > 0 && CSEQDIFF (iseq, iIrecseq) > iIrequest_winsize)) { - DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL, - "fiprocess_data: Ignoring out of order packet %d", - iseq); + DEBUG_MESSAGE2 (DEBUG_PROTO | DEBUG_ABNORMAL, + "fiprocess_data: Ignoring out of order packet %d (recseq %d)", + iseq, iIrecseq); continue; } else { - DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL, - "fiprocess_data: Saving unexpected packet %d", - iseq); + DEBUG_MESSAGE2 (DEBUG_PROTO | DEBUG_ABNORMAL, + "fiprocess_data: Saving unexpected packet %d (recseq %d)", + iseq, iIrecseq); if (azIrecbuffers[iseq] == NULL) { @@ -1352,7 +1404,7 @@ fiprocess_data (qdaemon, pfexit, pffound, pcneed) However, it can happen if we receive a burst of short packets, such as a set of command acknowledgements. */ if (iIrequest_winsize > 0 - && CSEQDIFF (iIrecseq, iIlocal_ack) >= iIrequest_winsize / 2) + && CSEQDIFF (iIrecseq, iIlocal_ack) >= cIack_frequency) { char aback[CHDRLEN]; @@ -1401,9 +1453,11 @@ fiprocess_packet (qdaemon, zhdr, zfirst, cfirst, zsecond, csecond, pfexit) boolean fret; iseq = IHDRWIN_GETSEQ (zhdr[IHDR_LOCAL]); - DEBUG_MESSAGE2 (DEBUG_PROTO, - "fiprocess_packet: Got DATA packet %d size %d", - iseq, cfirst + csecond); + DEBUG_MESSAGE4 (DEBUG_PROTO, + "fiprocess_packet: Got DATA packet %d size %d local %d remote %d", + iseq, cfirst + csecond, + IHDRWIN_GETCHAN (zhdr[IHDR_REMOTE]), + IHDRWIN_GETCHAN (zhdr[IHDR_LOCAL])); fret = fgot_data (qdaemon, zfirst, (size_t) cfirst, zsecond, (size_t) csecond, IHDRWIN_GETCHAN (zhdr[IHDR_REMOTE]), @@ -1417,7 +1471,7 @@ fiprocess_packet (qdaemon, zhdr, zfirst, cfirst, zsecond, csecond, pfexit) case SYNC: { - int ipack, iwin; + int ipack, iwin, cchans; /* We accept a SYNC packet to adjust the packet and window sizes at any time. */ @@ -1436,16 +1490,31 @@ fiprocess_packet (qdaemon, zhdr, zfirst, cfirst, zsecond, csecond, pfexit) else iwin = zsecond[2 - cfirst]; - DEBUG_MESSAGE2 (DEBUG_PROTO, - "fiprocess_packet: Got SYNC packsize %d winsize %d", - ipack, iwin); + /* The fourth byte in a SYNC packet is the number of channels + to use. This is optional. Switching the number of + channels in the middle of a conversation may cause + problems. */ + if (cfirst + csecond <= 3) + cchans = 0; + else + { + if (cfirst > 3) + cchans = zfirst[3]; + else + cchans = zsecond[3 - cfirst]; + if (cchans > 0 && cchans < 8) + qdaemon->cchans = cchans; + } + + DEBUG_MESSAGE3 (DEBUG_PROTO, + "fiprocess_packet: Got SYNC packsize %d winsize %d channels %d", + ipack, iwin, cchans); if (iIforced_remote_packsize == 0 && (iIalc_packsize == 0 || ipack <= iIalc_packsize)) iIremote_packsize = ipack; - if (iIforced_remote_winsize == 0) - iIremote_winsize = iwin; + iIremote_winsize = iwin; /* We increment a static variable to tell the initialization code that a SYNC was received, and we set *pfexit to TRUE @@ -1477,44 +1546,68 @@ fiprocess_packet (qdaemon, zhdr, zfirst, cfirst, zsecond, csecond, pfexit) iseq = IHDRWIN_GETSEQ (zhdr[IHDR_LOCAL]); - /* The timeout code will send a NAK for the packet the remote - side wants. So we may see a NAK here for the packet we are - about to send. */ - if (iseq == iIsendseq - || (iIremote_winsize > 0 - && (CSEQDIFF (iseq, iIremote_ack) > iIremote_winsize - || CSEQDIFF (iIsendseq, iseq) > iIremote_winsize))) + /* If the remote side times out while waiting for a packet, it + will send a NAK for the next packet it wants to see. If we + have not sent that packet yet, and we have no + unacknowledged data, it implies that the remote side has a + window full of data to send, which implies that our ACK has + been lost. Therefore, we send an ACK. */ + if (iseq == iIsendseq && + INEXTSEQ (iIremote_ack) == iIsendseq) { - DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL, - "fiprocess_packet: Ignoring out of order NAK %d", - iseq); - return TRUE; - } + char aback[CHDRLEN]; + + aback[IHDR_INTRO] = IINTRO; + aback[IHDR_LOCAL] = IHDRWIN_SET (0, 0); + aback[IHDR_REMOTE] = IHDRWIN_SET (iIrecseq, 0); + iIlocal_ack = iIrecseq; + aback[IHDR_CONTENTS1] = IHDRCON_SET1 (ACK, qdaemon->fcaller, 0); + aback[IHDR_CONTENTS2] = IHDRCON_SET2 (ACK, qdaemon->fcaller, 0); + aback[IHDR_CHECK] = IHDRCHECK_VAL (aback); - DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL, - "fiprocess_packet: Got NAK %d; resending packet", - iseq); + DEBUG_MESSAGE1 (DEBUG_PROTO, "fiprocess_packet: Sending ACK %d", + iIrecseq); - /* Update the received sequence number. */ - zsend = azIsendbuffers[iseq] + CHDROFFSET; - if (IHDRWIN_GETSEQ (zsend[IHDR_REMOTE]) != iIrecseq) + return (*pfIsend) (qdaemon->qconn, aback, CHDRLEN, TRUE); + } + else { - int iremote; + if (iseq == iIsendseq + || (iIremote_winsize > 0 + && (CSEQDIFF (iseq, iIremote_ack) > iIremote_winsize + || CSEQDIFF (iIsendseq, iseq) > iIremote_winsize))) + { + DEBUG_MESSAGE2 (DEBUG_PROTO | DEBUG_ABNORMAL, + "fiprocess_packet: Ignoring out of order NAK %d (sendseq %d)", + iseq, iIsendseq); + return TRUE; + } - iremote = IHDRWIN_GETCHAN (zsend[IHDR_REMOTE]); - zsend[IHDR_REMOTE] = IHDRWIN_SET (iIrecseq, iremote); - zsend[IHDR_CHECK] = IHDRCHECK_VAL (zsend); - iIlocal_ack = iIrecseq; - } + DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL, + "fiprocess_packet: Got NAK %d; resending packet", + iseq); + + /* Update the received sequence number. */ + zsend = azIsendbuffers[iseq] + CHDROFFSET; + if (IHDRWIN_GETSEQ (zsend[IHDR_REMOTE]) != iIrecseq) + { + int iremote; + + iremote = IHDRWIN_GETCHAN (zsend[IHDR_REMOTE]); + zsend[IHDR_REMOTE] = IHDRWIN_SET (iIrecseq, iremote); + zsend[IHDR_CHECK] = IHDRCHECK_VAL (zsend); + iIlocal_ack = iIrecseq; + } - ++cIresent_packets; + ++cIresent_packets; - clen = CHDRCON_GETBYTES (zsend[IHDR_CONTENTS1], - zsend[IHDR_CONTENTS2]); + clen = CHDRCON_GETBYTES (zsend[IHDR_CONTENTS1], + zsend[IHDR_CONTENTS2]); - return (*pfIsend) (qdaemon->qconn, zsend, - CHDRLEN + clen + (clen > 0 ? CCKSUMLEN : 0), - TRUE); + return (*pfIsend) (qdaemon->qconn, zsend, + CHDRLEN + clen + (clen > 0 ? CCKSUMLEN : 0), + TRUE); + } } case SPOS: |