|
|
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.