|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.