|
|
1.1 root 1: /* protz.c Version 1.5, 92Apr24 */
2: /* Modified by Ian Lance Taylor for Taylor UUCP 1.04 92Aug4. */
3:
4: /*
5: * Doug Evans, [email protected] or [email protected]
6: *
7: * This file provides the Zmodem protocol (by Chuck Forsberg) for
8: * Ian Taylor's UUCP package.
9: *
10: * It was originally developed to establish a uucp link between myself and my
11: * employer: Ivation Datasystems, Inc. of Ottawa.
12: *
13: * My thanks to Ivation for letting me release this to the public. Given that
14: * Zmodem is in the public domain, no additional copyrights have been added.
15: *
16: *****************************************************************************
17: *
18: * It's been difficult fitting Zmodem into the UUCP world. I have been guided
19: * mostly by trying to plug it into Taylor UUCP. Where "the Zmodem way of doing
20: * things" conflicted with "the UUCP way of doing things", I have err'd on the
21: * side of UUCP. At the end of it all, I have achieved something that will plug
22: * into Taylor UUCP very easily, but some might argue that I have corrupted Z
23: * too much. At any rate, compatibility with sz/rz was sacrificed to achieve a
24: * clean UUCP protocol. Given that, I took the opportunity to start from
25: * scratch when defining protocol constants (EG: ZBIN).
26: *
27: * 1) I wasn't quite sure how to enhance Zmodem to handle send+receive in one
28: * session, so I added a 'g' protocol like initialization sequence. This
29: * also gets this stuff out of the way, in case we ever try to support
30: * full-duplex.
31: *
32: * Caller Callee
33: * ------ ------
34: * ZINIT --> <-- ZINIT
35: * ZDATA (ZCRCF) --> <-- ZDATA (ZCRCF)
36: * ZACK --> <-- ZACK
37: * ZINITEND --> <-- ZINITEND
38: *
39: * ZINIT is a combination of ZRINIT and ZSINIT and is intended to exchange
40: * simple protocol information (flags) and the protocol version number.
41: * ZDATA is intended to include window size information as well as the
42: * "Myattn" string (although at the moment it doesn't contain anything).
43: * ZDATA may contain at most 1k bytes of data and is sent out as one ZCRCF
44: * packet. Two ack's (ZACK + ZINITEND) are needed to ensure both sides have
45: * received ZDATA.
46: *
47: * 2) I've hardcoded several protocol parameters, like 32 bit CRC's for data.
48: * Others are not supported (we don't need them).
49: *
50: * 3) ZHEX headers use 32 bit CRC's.
51: *
52: * 4) Zmodem sends the ZFILE message "in one chunk". If there are errors, the
53: * entire string is resent. I have continued this practice. All UUCP
54: * commands are sent "in one chunk". This can be changed down the road if
55: * necessary.
56: *
57: * 5) The ZEOF message has been replaced with a new ZCRCx value: ZCRCF. ZCRCF
58: * is identical to ZCRCW except that it indicates the end of the message.
59: * The protocol here is *not* a file transfer protocol. It is an end to end
60: * transport protocol (that preserves message boundaries).
61: *
62: * 6) Zmodem handles restarting a file transfer, but as best as I can tell UUCP
63: * does not. At least Taylor UUCP doesn't. And if UUCP does start handling
64: * file restart, can it be plugged into the existing Zmodem way with zero
65: * changes? Beats me. Therefore I have removed this part of the code. One
66: * can always put it back in if and when UUCP handles it. Ditto for other
67: * pieces of removed code: there's no point in overly complicating this code
68: * when supporting all the bells and whistles requires enhancements to UUCP
69: * itself.
70: *
71: * *** It is easier to put code back in in an upward compatible manner ***
72: * *** than it is to correct for misunderstood code or poorly merged ***
73: * *** (Zmodem vs UUCP) code. ***
74: *
75: * 7) For the character in the initial "protocol selection" sequence, I have
76: * chosen 'a'. I'm told 'z' is already in use for something that isn't
77: * Zmodem. It's entirely reasonable to believe that if Zmodem ever becomes a
78: * standard UUCP protocol, this won't be it (so I'll leave z/Z for them).
79: * Publicly, this is the 'a' protocol. Internally, it is refered to as 'z'.
80: * A little confusing, I know. Maybe in time I'll refer to it internally as
81: * 'a', or maybe in time this will be *the* 'z' protocol.
82: *
83: * 8) Since we are writing a transport protocol, which isn't supposed to know
84: * anything about what is being transfered or where it is coming from, the
85: * header data value has changed meaning. It no longer means "file position"
86: * but instead means "window position". It is a running counter of the bytes
87: * transfered. Each "message" begins on a 1k boundary so the count isn't a
88: * precise byte count. The counter wraps every 4 gigabytes, although this
89: * wrapping isn't supported yet.
90: *
91: * FIXME: At present the max data transfered per session is 4 gigabytes.
92: *
93: ****************************************************************************
94: *
95: * A typical message sequence is (master sending file to slave):
96: *
97: * Master Slave
98: * ------ -----
99: * ZDATA (S, ZCRCF) -->
100: * <-- ZACK
101: * <-- ZDATA (SY, ZCRCF)
102: * ZACK -->
103: * ZDATA -->
104: * ... <-- ZACK/ZRPOS
105: * ZDATA (ZCRCF) -->
106: * <-- ZACK
107: * <-- ZDATA (CY, ZCRCF)
108: * ZACK -->
109: *
110: * A typical message sequence is (master receiving file from slave):
111: *
112: * Master Slave
113: * ------ -----
114: * ZDATA (R, ZCRCF) -->
115: * <-- ZACK
116: * <-- ZDATA (RY, ZCRCF)
117: * ZACK -->
118: * <-- ZDATA
119: * ZACK/ZRPOS ... -->
120: * <-- ZDATA (ZCRCF)
121: * ZACK -->
122: * ZDATA (CY, ZCRCF) -->
123: * <-- ZACK
124: *
125: *****************************************************************************
126: *
127: * Notes:
128: * 1) For future bidirectional concerns, keep packet types "unidirectional".
129: * Sender always uses: ZDATA, ZNAK
130: * Receiver always uses: ZRPOS, ZACK
131: * There is no intersection.
132: *
133: * I'm not sure if this is necessary or even useful, but it seems to be.
134: *
135: * 2) I use to store the byte count / 32 in the data header. This left 5 bits
136: * unused for future concerns. I removed this because of the following
137: * situation when sending a file:
138: *
139: * ZDATA (ZCRCG, xx bytes) - received ok
140: * ZDATA (ZCRCF, 0 bytes) - corrupted
141: *
142: * At this point the receiver would like to send back a ZRPOS with a value
143: * of the size of the file. However, it can't because the value is divided
144: * by 32, and it would have to round up to the next multiple of 32. This
145: * seemed a little ugly, so I went with using the entire header to store
146: * the byte count.
147: *
148: *****************************************************************************
149: *
150: * Source version:
151: *
152: * 1.1,2,3
153: * Protocol version 0
154: * Early attempts, completely rewritten later.
155: *
156: * 1.4 Protocol version 1
157: * Beta test sent to Ian for analysis 92Apr18.
158: *
159: * 1.5 Protocol version 1
160: * Released 92Apr24.
161: *
162: *****************************************************************************
163: *
164: * Protocol version:
165: *
166: * A version number is exchanged in the ZINIT message, so it is possible to
167: * correct or enhance the protocol, without breaking existing versions.
168: * The purpose of this section is to document these versions as they come out.
169: * Remember, this is the protocol version, not the source version.
170: *
171: * 0 Initial version.
172: * Zmodem controlled file transfer. This was more of a "plug Z
173: * into UUCP as is" port.
174: *
175: * 1 Complete rewrite.
176: * Made Z more of a transport protocol. UUCP now controls transfer and Z
177: * is on the same footing as the other UUCP protocols.
178: * Theoretically, there will be little pain when UUCP goes bidirectional.
179: */
180:
181: #include "uucp.h"
182:
183: #if USE_RCS_ID
184: const char protz_rcsid[] = "$Id: protz.c,v 1.1 93/07/30 07:53:39 bin Exp Locker: bin $";
185: #endif
186:
187: #include <errno.h>
188:
189: #include "uudefs.h"
190: #include "uuconf.h"
191: #include "conn.h"
192: #include "trans.h"
193: #include "system.h"
194: #include "prot.h"
195:
196: #define ZPROTOCOL_VERSION 1
197:
198: /*
199: * Control message characters ...
200: */
201:
202: #define ZPAD '*' /* Padding character begins frames */
203: #define ZDLE 030 /* Ctrl-X Zmodem escape - `ala BISYNC DLE */
204: #define ZBIN 'A' /* Binary frame indicator */
205: #define ZHEX 'B' /* HEX frame indicator */
206:
207: /*
208: * Frame types (see array "frametypes" in zm.c) ...
209: *
210: * Note that the numbers here have been reorganized, as we don't support
211: * all of them (nor do we need to).
212: *
213: * WARNING: The init sequence assumes ZINIT < ZDATA < ZACK < ZINITEND.
214: */
215:
216: #define ZINIT 0 /* Init (contains protocol version, flags) */
217: #define ZDATA 1 /* Data packet(s) follow */
218: #define ZRPOS 2 /* Resume data trans at this position */
219: #define ZACK 3 /* ACK to above */
220: #define ZNAK 4 /* Last packet was garbled */
221: #define Zreserved 5 /* reserved (for future concerns) */
222: #define ZINITEND 6 /* end of init sequence */
223: #define ZFIN 7 /* Finish session */
224:
225: /*
226: * ZDLE sequences ...
227: *
228: * Note addition of ZCRCF: "end of message".
229: */
230:
231: #define ZCRCE 'h' /* CRC next, frame ends, header packet follows */
232: #define ZCRCG 'i' /* CRC next, frame continues nonstop */
233: #define ZCRCQ 'j' /* CRC next, frame continues, ZACK expected */
234: #define ZCRCW 'k' /* CRC next, ZACK expected, end of frame */
235: #define ZCRCF 'l' /* CRC next, ZACK expected, end of message */
236:
237: #define ZRUB0 'm' /* Translate to rubout 0177 */
238: #define ZRUB1 'n' /* Translate to rubout 0377 */
239:
240:
241: /*
242: * zdlread return values (internal) ...
243: * Other values are ZM_ERROR, ZM_TIMEOUT, ZM_RCDO.
244: */
245:
246: #define GOTOR 0400
247: #define GOTCRCE (ZCRCE | GOTOR) /* ZDLE-ZCRCE received */
248: #define GOTCRCG (ZCRCG | GOTOR) /* ZDLE-ZCRCG received */
249: #define GOTCRCQ (ZCRCQ | GOTOR) /* ZDLE-ZCRCQ received */
250: #define GOTCRCW (ZCRCW | GOTOR) /* ZDLE-ZCRCW received */
251: #define GOTCRCF (ZCRCF | GOTOR) /* ZDLE-ZCRCF received */
252:
253: /*
254: * Byte positions within header array ...
255: */
256:
257: #define ZF0 3 /* First flags byte */
258: #define ZF1 2
259: #define ZF2 1
260: #define ZF3 0
261:
262: #define ZP0 0 /* Low order 8 bits of position */
263: #define ZP1 1
264: #define ZP2 2
265: #define ZP3 3 /* High order 8 bits of position */
266:
267: /*
268: * Bit Masks for ZRQINIT flags byte ZF0 ...
269: */
270:
271: #define TX_ESCCTL 1 /* Tx will escape control chars */
272:
273: /*
274: * Possible errors when running ZMODEM ...
275: */
276:
277: #define ZM_ERROR (-1) /* crc error, etc. */
278: #define ZM_TIMEOUT (-2)
279: #define ZM_RCDO (-3) /* Carrier Lost */
280:
281: /*
282: * ASCII characters ...
283: */
284:
285: #define LF 012
286: #define CR 015
287: #define XON 021
288: #define XOFF 023
289:
290: #define XON_WAIT 10 /* seconds */
291:
292: /*
293: * Packet sizes ...
294: *
295: * FIXME: CPACKETSIZE is hardcoded in a lot of places.
296: * It's not clear to me whether changing it's value would be a
297: * "good thing" or not. But of course that doesn't excuse the hardcoding.
298: */
299:
300: #define CPACKETSIZE 1024 /* max packet size (data only) */
301: #define CFRAMELEN 12 /* header size */
302: #define CSUFFIXLEN 10 /* suffix at end of data packets */
303: #define CEXCHANGE_INIT_RETRIES 4
304:
305: /* The header CRC value. */
306:
307: #if ANSI_C
308: #define IHDRCRC 0xDEBB20E3UL
309: #else
310: #define IHDRCRC ((unsigned long) 0xDEBB20E3L)
311: #endif
312:
313: /* packet buffer size */
314: #define CPACKBUFSIZE (CFRAMELEN + 2 * CPACKETSIZE + CSUFFIXLEN + 42 /*slop*/)
315:
316: /*
317: * Data types ...
318: */
319:
320: typedef unsigned char achdrval_t[4];
321: typedef unsigned long hdrval_t;
322: typedef unsigned long winpos_t;
323:
324: /*
325: * Configurable parms ...
326: *
327: * FIXME: <cZrx_buf_len> isn't used yet. It may not be needed.
328: */
329:
330: #define CTIMEOUT 10
331: #define CRETRIES 10
332: #define CSTARTUP_RETRIES 4
333: #define CGARBAGE 2400
334: #define CSEND_WINDOW 16384
335: #define FESCAPE_CONTROL FALSE
336:
337: static int cZtimeout = CTIMEOUT; /* (seconds) */
338: static int cZretries = CRETRIES;
339: static int cZstartup_retries = CSTARTUP_RETRIES;
340: static int cZmax_garbage = CGARBAGE; /* max garbage before header */
341: static int cZtx_window = CSEND_WINDOW; /* our transmission window */
342: static int cZrx_buf_len = 0; /* our reception buffer size */
343: static boolean fZesc_ctl = FESCAPE_CONTROL; /* escape control chars */
344:
345: struct uuconf_cmdtab asZproto_params[] =
346: {
347: {"timeout", UUCONF_CMDTABTYPE_INT, (pointer) & cZtimeout, NULL},
348: {"retries", UUCONF_CMDTABTYPE_INT, (pointer) & cZretries, NULL},
349: {"startup-retries", UUCONF_CMDTABTYPE_INT,
350: (pointer) & cZstartup_retries, NULL},
351: {"garbage", UUCONF_CMDTABTYPE_INT, (pointer) & cZmax_garbage, NULL},
352: {"send-window", UUCONF_CMDTABTYPE_INT, (pointer) & cZtx_window, NULL},
353: {"escape-control", UUCONF_CMDTABTYPE_BOOLEAN, (pointer) & fZesc_ctl,
354: NULL},
355: {NULL, 0, NULL, NULL}
356: };
357:
358: /*
359: * Variables for statistic gathering ...
360: *
361: * We use <wpZtxpos, wpZrxbytes> to record the number of "packets"
362: * sent/received. Packets is in double quotes because some of them aren't full.
363: */
364:
365: static unsigned long cZheaders_sent;
366: static unsigned long cZheaders_received;
367: static unsigned long cZbytes_resent;
368: static unsigned long cZtimeouts;
369: static unsigned long cZerrors;
370:
371: /*
372: * Data buffers ...
373: */
374:
375: static char *zZtx_buf; /* transmit buffer */
376:
377: static char *zZtx_packet_buf; /* raw outgoing packet data */
378: static char *zZrx_packet_buf; /* raw incoming packet data */
379:
380: /*
381: * Transmitter state variables ...
382: */
383:
384: static unsigned cZblklen; /* data length in sent/received packets */
385: static unsigned cZtxwspac; /* spacing between ZCRCQ requests */
386: /*static unsigned cZblklen_override;*//* override value for <cZblklen> */
387: static unsigned cZtxwcnt; /* counter used to space ack requests */
388: static unsigned cZrxwcnt; /* counter used to watch receiver's buf size */
389: static winpos_t wpZtxstart; /* <wpZtxpos> when message started */
390: static winpos_t wpZtxpos; /* transmitter position */
391: static winpos_t wpZlastsync; /* last offset to which we got a ZRPOS */
392: static winpos_t wpZlrxpos; /* receiver's last reported offset */
393: static winpos_t wpZrxpos; /* receiver file position */
394:
395: static int iZlast_tx_data_packet; /* type of last ZDATA packet (ZCRCx) */
396: static int iZjunk_count; /* amount of garbage characters received */
397: static int iZtleft; /* for dynamic packet resizing */
398:
399: static int iZbeenhereb4; /* times we've been ZRPOS'd to same place */
400:
401: /*
402: * Receiver state variables ...
403: */
404:
405: static winpos_t wpZrxbytes; /* receiver byte count */
406: static int iZlast_rx_data_packet; /* last successfully received ZCRCx packet */
407:
408: /*
409: * Misc. globals ...
410: */
411:
412: static char xon = XON;
413:
414: #ifdef DJE_TESTING
415: int uucptest = -1;
416: int uucptest2;
417: int uucptestseed;
418: #endif
419:
420: /*
421: * Kludge!!!
422: * See fzfinish_tx(). Basically the next two globals are used to record the
423: * fact that we got a ZDATA, but aren't quite ready to process it.
424: */
425:
426: static int iZpkt_rcvd_kludge; /* -1 if not valid */
427: static hdrval_t hvZpkt_hdrval_kludge;
428:
429: /*
430: * Packet types ...
431: */
432:
433: static const char *azZframe_types[] = {
434: "Carrier Lost", /* -3 */
435: "Timeout", /* -2 */
436: "Error", /* -1 */
437: #define FTOFFSET 3
438: "ZINIT",
439: "ZDATA",
440: "ZRPOS",
441: "ZACK",
442: "ZNAK",
443: "Zreserved",
444: "ZINITEND",
445: "ZFIN",
446: "UNKNOWN!!!"
447: };
448: #define FTNUMBER (sizeof(azZframe_types) / sizeof(char *))
449:
450: #ifndef min
451: #define min(a, b) ((a) < (b) ? (a) : (b))
452: #endif
453: #define ZZHEADER_NAME(itype) \
454: azZframe_types[min((itype) + FTOFFSET, FTNUMBER - 1)]
455:
456: /*
457: * Local functions ...
458: */
459:
460: static boolean fzsend_data P((struct sdaemon *qdaemon, char *zdata,
461: size_t cdata, boolean fendofmessage));
462: static boolean fzprocess P((struct sdaemon *qdaemon));
463: static boolean fzstart_proto P((struct sdaemon *qdaemon));
464: static int izexchange_init P((struct sdaemon *qdaemon, int send_type,
465: achdrval_t send_val, achdrval_t recv_val));
466: static boolean fzshutdown_proto P((struct sdaemon *qdaemon));
467: static boolean fzstart_tx P((void));
468: static boolean fzfinish_tx P((struct sdaemon *qdaemon, long *plredo));
469: static boolean fzstart_rx P((void));
470: static boolean fzfinish_rx P((struct sdaemon *qdaemon));
471: static boolean fzsend_hdr P((struct sdaemon *qdaemon, int ipkttype,
472: int ihdrtype, hdrval_t hdrval,
473: boolean fcheckreceive));
474: static boolean fzsend_data_packet P((struct sdaemon *qdaemon, char *zdata,
475: size_t cdata, int frameend,
476: boolean fcheckreceive));
477: static int czbuild_header P((char *zresult, int ipkttype, int ihdrtype,
478: hdrval_t hdrval));
479: static int czbuild_data_packet P((char *zresult, const char *zdata,
480: size_t cdata, int frameend));
481: /*
482: * The rest of the functions do not follow Ian's naming style. I have left
483: * the names the same as the original zm source. Over time, they may change.
484: */
485: static int izrecv_hdr P((struct sdaemon *qdaemon, achdrval_t hdr));
486: static int zrbhdr32 P((struct sdaemon *qdaemon, achdrval_t hdr));
487: static int zrhhdr P((struct sdaemon *qdaemon, achdrval_t hdr));
488: static int zrdat32 P((struct sdaemon *qdaemon, char *buf, int length,
489: int *iprxcount));
490: static int getinsync P((struct sdaemon *qdaemon, boolean flag));
491: static char *zputhex P((char *p, int ch));
492: static char *zputchar P((char *p, int ch));
493: static int zgethex P((struct sdaemon *qdaemon));
494: static int zdlread P((struct sdaemon *qdaemon));
495: static int noxrd7 P((struct sdaemon *qdaemon));
496: static int realreadchar P((struct sdaemon *qdaemon, int timeout));
497: static boolean fzreceive_ready P((void));
498: static void stohdr P((hdrval_t pos, achdrval_t hdr));
499: static hdrval_t rclhdr P((achdrval_t hdr));
500: static hdrval_t hvzencode_data_hdr P((winpos_t cbytes));
501: static void zdecode_data_hdr P((hdrval_t hdrval, winpos_t *pcbytes));
502: static winpos_t lzupdate_rxpos P((achdrval_t rx_hdr, winpos_t rxpos,
503: winpos_t lrxpos, winpos_t txpos));
504:
505: /*
506: * This macro replaces readchar() because it achieves a noticable speed up. The
507: * readchar() function has been renamed realreadchar(). Thanks to Ian for
508: * running this stuff through a profiler to find this out. Ian suggests further
509: * speed ups may be obtained by doing a similar thing in zrdat32().
510: */
511:
512: /* Assign the next character to b. */
513: #define READCHAR(qdaemon, b, i) \
514: (iPrecstart != iPrecend \
515: ? ((b) = BUCHAR (abPrecbuf[iPrecstart]), \
516: iPrecstart = (iPrecstart + 1) % CRECBUFLEN) \
517: : ((b) = realreadchar ((qdaemon), (i))))
518:
519: /************************************************************************/
520:
521:
522: /*
523: * Start the protocol ...
524: */
525:
526: boolean
527: fzstart(qdaemon, pzlog)
528: struct sdaemon *qdaemon;
529: char **pzlog;
530: {
531: *pzlog = zbufalc (sizeof "protocol 'a' starting: , , , , , " + 100);
532: sprintf (*pzlog, "protocol 'a' starting: %d, %d, %d, %d, %d, %d",
533: cZtimeout, cZretries, cZstartup_retries,
534: cZmax_garbage, cZtx_window, fZesc_ctl);
535:
536: if (! fconn_set (qdaemon->qconn, PARITYSETTING_NONE,
537: STRIPSETTING_EIGHTBITS, XONXOFF_OFF))
538: return FALSE;
539:
540: /*
541: * For now, we place tight restrictions on the size of the transmit
542: * window. This might be relaxed in the future. If it is relaxed,
543: * some of these tests will stay, some will go. That is why it is
544: * coded like it is.
545: */
546:
547: if (cZtx_window % 1024 != 0 ||
548: cZtx_window < 4096 || cZtx_window > 65536 ||
549: 65536 % cZtx_window != 0
550: ) {
551: ulog (LOG_ERROR,
552: "fzstart: cZtx_window not one of 4096, 8192, 16384, 32768, 65536");
553: return FALSE;
554: }
555:
556: zZtx_buf = (char *) xmalloc (CPACKETSIZE);
557: zZtx_packet_buf = (char *) xmalloc (CPACKBUFSIZE);
558: zZrx_packet_buf = (char *) xmalloc (CPACKBUFSIZE);
559:
560: iZlast_tx_data_packet = -1;
561: iZlast_rx_data_packet = -1;
562:
563: wpZtxpos = wpZlrxpos = wpZrxpos = wpZrxbytes = 0;
564: cZtxwspac = cZtx_window / 4;
565:
566: cZheaders_sent = cZheaders_received = cZbytes_resent = 0;
567: cZtimeouts = cZerrors = 0;
568:
569: iZpkt_rcvd_kludge = -1;
570:
571: #if 0
572: /*
573: * We ensure <cZtx_window> is at least 4k, so the following is
574: * unnecessary. It can be put back in later if needed.
575: */
576: if (cZblklen_override > cZtxwspac
577: || (!cZblklen_override && cZtxwspac < 1024))
578: cZblklen_override = cZtxwspac;
579: #endif
580:
581: #ifdef DJE_TESTING
582: {
583: extern int uucptest,uucptest2,uucptestseed;
584: FILE *f;
585:
586: if (uucptest == -1) {
587: f = fopen ("/usr/local/src/bin/uucp/uucptest", "r");
588: if (f != NULL) {
589: fscanf (f, "%d %d %d",
590: &uucptestseed, &uucptest, &uucptest2);
591: fclose (f);
592: }
593: srand (uucptestseed);
594: }
595: }
596: #endif
597:
598: /*
599: * Fire up the protocol (exchange init messages) ...
600: */
601:
602: if (!fzstart_proto (qdaemon))
603: return FALSE;
604:
605: return TRUE;
606: }
607:
608: /*
609: * Stop the protocol ...
610: */
611:
612: boolean
613: fzshutdown(qdaemon)
614: struct sdaemon *qdaemon;
615: {
616: (void) fzshutdown_proto (qdaemon);
617:
618: xfree ((pointer) zZtx_buf);
619: xfree ((pointer) zZtx_packet_buf);
620: xfree ((pointer) zZrx_packet_buf);
621: zZtx_buf = NULL;
622: zZtx_packet_buf = NULL;
623: zZrx_packet_buf = NULL;
624:
625: /*
626: * Print some informative statistics ...
627: *
628: * I use the word "messages" here instead of "headers" because the
629: * latter is jargonese.
630: */
631:
632: ulog (LOG_NORMAL,
633: "Protocol 'a' messages: sent %lu, received %lu",
634: cZheaders_sent, cZheaders_received);
635: ulog (LOG_NORMAL,
636: "Protocol 'a' packets: sent %lu, received %lu",
637: wpZtxpos / 1024, wpZrxbytes / 1024);
638: if (cZbytes_resent != 0 || cZtimeouts != 0 || cZerrors != 0)
639: ulog (LOG_NORMAL,
640: "Protocol 'a' errors: bytes resent %lu, timeouts %lu, errors %lu",
641: cZbytes_resent, cZtimeouts, cZerrors);
642:
643: /*
644: * Reset all the parameters to their default values, so that the
645: * protocol parameters used for this connection do not affect the
646: * next one.
647: */
648:
649: cZtimeout = CTIMEOUT;
650: cZretries = CRETRIES;
651: cZstartup_retries = CSTARTUP_RETRIES;
652: cZmax_garbage = CGARBAGE;
653: cZtx_window = CSEND_WINDOW;
654: fZesc_ctl = FESCAPE_CONTROL;
655:
656: cZheaders_sent = cZheaders_received = cZbytes_resent = 0;
657: cZtimeouts = cZerrors = 0;
658:
659: return TRUE;
660: }
661:
662: /*
663: * Send a command string ...
664: * We send everything up to and including the null byte.
665: *
666: * We assume the command will fit in the outgoing data buffer.
667: * FIXME: A valid assumption?
668: */
669:
670: /*ARGSUSED*/
671: boolean
672: fzsendcmd(qdaemon, z, ilocal, iremote)
673: struct sdaemon *qdaemon;
674: const char *z;
675: int ilocal;
676: int iremote;
677: {
678: size_t n,clen;
679: long lredo;
680: char *zbuf;
681:
682: clen = strlen (z) + 1;
683:
684: DEBUG_MESSAGE1 (DEBUG_PROTO, "fzsendcmd: sending command %s", z);
685:
686: if (!fzstart_tx ()) /* must be called before zzgetspace() */
687: return FALSE;
688:
689: if ((zbuf = zzgetspace (qdaemon, &n)) == NULL)
690: return FALSE;
691:
692: #if DEBUG > 0
693: if (clen > n)
694: ulog (LOG_FATAL, "fzsendcmd: clen > n");
695: #endif
696:
697: strcpy (zbuf, z);
698:
699: /*
700: * Send it out ...
701: */
702:
703: do {
704: if (!fzsend_data (qdaemon, zbuf, clen, TRUE))
705: return FALSE;
706: if (!fzfinish_tx (qdaemon, &lredo))
707: return FALSE;
708: } while (lredo >= 0);
709:
710: return fzprocess (qdaemon);
711: }
712:
713: /*
714: * Allocate a packet to send out ...
715: *
716: * Note that 'z' has dynamic packet resizing and that <cZblklen> will range
717: * from 32 to 1024, in multiples of 2.
718: */
719:
720: /*ARGSUSED*/
721: char *
722: zzgetspace(qdaemon, pclen)
723: struct sdaemon *qdaemon;
724: size_t *pclen;
725: {
726: *pclen = cZblklen;
727: return zZtx_buf;
728: }
729:
730: /*
731: * Send a block of data ...
732: *
733: * If (cdata == 0) then the end of the file has been reached.
734: */
735:
736: /*ARGSUSED*/
737: boolean
738: fzsenddata(qdaemon, zdata, cdata, ilocal, iremote, ipos)
739: struct sdaemon *qdaemon;
740: char *zdata;
741: size_t cdata;
742: int ilocal;
743: int iremote;
744: long ipos;
745: {
746: DEBUG_MESSAGE1 (DEBUG_PROTO, "fzsenddata: %d bytes", cdata);
747:
748: if (! fzsend_data (qdaemon, zdata, cdata, cdata == 0))
749: return FALSE;
750: return fzprocess (qdaemon);
751: }
752:
753: /*
754: * Send a block of data (command or file) ...
755: */
756:
757: /* This should buffer the data internally. Until it does, it needs to
758: be able to reset the file position when it is called. This is
759: really ugly. */
760: extern struct stransfer *qTsend;
761:
762: static boolean
763: fzsend_data(qdaemon, zdata, cdata, fendofmessage)
764: struct sdaemon *qdaemon;
765: char *zdata;
766: size_t cdata;
767: boolean fendofmessage;
768: {
769: size_t n;
770:
771: if (iZlast_tx_data_packet == -1 || iZlast_tx_data_packet == ZCRCW) {
772: cZtxwcnt = cZrxwcnt = 0;
773: iZjunk_count = 0;
774: if (!fzsend_hdr (qdaemon, ZBIN, ZDATA,
775: hvzencode_data_hdr (wpZtxpos), TRUE))
776: return FALSE;
777: }
778:
779: n = cdata;
780:
781: if (fendofmessage)
782: iZlast_tx_data_packet = ZCRCF;
783: else if (iZjunk_count > 3)
784: iZlast_tx_data_packet = ZCRCW;
785: else if (wpZtxpos == wpZlastsync)
786: iZlast_tx_data_packet = ZCRCW;
787: else if (cZrx_buf_len && (cZrxwcnt += n) >= cZrx_buf_len)
788: iZlast_tx_data_packet = ZCRCW;
789: else if ((cZtxwcnt += n) >= cZtxwspac) {
790: iZlast_tx_data_packet = ZCRCQ;
791: cZtxwcnt = 0;
792: } else
793: iZlast_tx_data_packet = ZCRCG;
794:
795: if (++iZtleft > 3) {
796: iZtleft = 0;
797: if (cZblklen < 1024)
798: cZblklen *= 2;
799: #if 0 /* <cZblklen_override> is currently unnecessary */
800: if (cZblklen_override && cZblklen > cZblklen_override)
801: cZblklen = cZblklen_override;
802: #endif
803: if (cZblklen > 1024)
804: cZblklen = 1024;
805: if (cZrx_buf_len && cZblklen > cZrx_buf_len)
806: cZblklen = cZrx_buf_len;
807: }
808:
809: #if DEBUG > 1
810: if (FDEBUGGING(DEBUG_PROTO)) {
811: const char *type;
812:
813: switch (iZlast_tx_data_packet) {
814: case ZCRCW: type = "ZCRCW"; break;
815: case ZCRCG: type = "ZCRCG"; break;
816: case ZCRCQ: type = "ZCRCQ"; break;
817: case ZCRCE: type = "ZCRCE"; break;
818: case ZCRCF: type = "ZCRCF"; break;
819: default : type = "UNKNOWN!!!"; break;
820: }
821: DEBUG_MESSAGE3 (DEBUG_PROTO,
822: "fzsend_data: %s, pos 0x%lx, %d bytes",
823: type, wpZtxpos, n);
824: }
825: #endif
826:
827: if (!fzsend_data_packet (qdaemon, zdata, n, iZlast_tx_data_packet,
828: TRUE))
829: return FALSE;
830:
831: wpZtxpos += n;
832:
833: if (iZlast_tx_data_packet == ZCRCW) {
834: /*
835: * FIXME: Ideally this would be done in fzprocess. However, it
836: * is only called if there is data pending which there
837: * may not be yet. I could have patched fploop() a bit but
838: * for now, I've done it like this.
839: */
840: switch (getinsync (qdaemon, FALSE)) {
841: case ZACK:
842: break;
843: case ZRPOS:
844: if (qTsend == NULL
845: || ! ffileisopen (qTsend->e)) {
846: ulog (LOG_ERROR, "Can't reset non-file");
847: return FALSE;
848: }
849: iZlast_tx_data_packet = -1; /* trigger ZDATA */
850: DEBUG_MESSAGE1 (DEBUG_PROTO,
851: "fzsend_data: Seeking to %ld",
852: (long) (wpZrxpos - wpZtxstart));
853: if (!ffileseek (qTsend->e, wpZrxpos - wpZtxstart)) {
854: ulog (LOG_ERROR, "seek: %s", strerror (errno));
855: return FALSE;
856: }
857: break;
858: default:
859: return FALSE;
860: }
861: return TRUE;
862: }
863:
864: /*
865: * If we've reached the maximum transmit window size, let the
866: * receiver catch up ...
867: *
868: * I use (cZtx_window - 2048) to play it safe.
869: */
870:
871: while (wpZtxpos - wpZlrxpos >= cZtx_window - 2048) {
872: if (iZlast_tx_data_packet != ZCRCQ) {
873: if (!fzsend_data_packet (qdaemon, zdata, (size_t) 0,
874: iZlast_tx_data_packet = ZCRCQ,
875: TRUE))
876: return FALSE;
877: }
878: /*
879: * FIXME: I'd rather not call ffileseek() in this file. When we
880: * start buffering the outgoing data, the following
881: * ffileseek() will disappear.
882: */
883: switch (getinsync (qdaemon, TRUE)) {
884: case ZACK:
885: break;
886: case ZRPOS:
887: if (qTsend == NULL
888: || ! ffileisopen (qTsend->e)) {
889: ulog (LOG_ERROR, "Can't reset non-file");
890: return FALSE;
891: }
892: iZlast_tx_data_packet = -1; /* trigger ZDATA */
893: DEBUG_MESSAGE1 (DEBUG_PROTO,
894: "fzsend_data: Seeking to %ld",
895: (long) (wpZrxpos - wpZtxstart));
896: if (!ffileseek (qTsend->e, wpZrxpos - wpZtxstart)) {
897: ulog (LOG_ERROR, "seek: %s", strerror (errno));
898: return FALSE;
899: }
900: break;
901: default:
902: return FALSE;
903: }
904: }
905:
906: return TRUE;
907: }
908:
909: /*
910: * Process existing data ...
911: */
912:
913: static boolean
914: fzprocess(qdaemon)
915: struct sdaemon *qdaemon;
916: {
917: int c,ch;
918:
919: while (fzreceive_ready ()) {
920: READCHAR (qdaemon, ch, 1);
921: switch (ch) {
922: case ZPAD:
923: /* see if we're detecting ZRPOS packets quickly */
924: DEBUG_MESSAGE0 (DEBUG_PROTO,
925: "fzprocess: possible ZRPOS packet");
926: /* We just ate the ZPAD char that getinsync
927: expects, so put it back. */
928: iPrecstart = ((iPrecstart + CRECBUFLEN - 1)
929: % CRECBUFLEN);
930: c = getinsync (qdaemon, TRUE);
931: if (c == ZACK)
932: break;
933: /* FIXME: sz does a TCFLSH here */
934: #if 0 /* FIXME: Not sure if this is needed, or where to put it. */
935: /* ZCRCE - dinna wanna starta ping-pong game */
936: if (!fzsend_data_packet (qdaemon, zZtx_packet_buf,
937: 0, ZCRCE, TRUE))
938: return FALSE;
939: #endif
940: if (c == ZRPOS) {
941: if (qTsend == NULL
942: || ! ffileisopen (qTsend->e)) {
943: ulog (LOG_ERROR,
944: "Attempt to back up non-file");
945: return FALSE;
946: }
947: if (! ffileseek (qTsend->e,
948: wpZrxpos - wpZtxstart)) {
949: ulog (LOG_ERROR,
950: "seek: %s", strerror (errno));
951: return FALSE;
952: }
953: iZlast_tx_data_packet = -1; /* trigger ZDATA */
954: break; /* not returning is intentional */
955: }
956: return FALSE;
957: case XOFF:
958: case XOFF | 0200:
959: READCHAR (qdaemon, ch, XON_WAIT);
960: break;
961: case CR:
962: break;
963: default:
964: iZjunk_count++;
965: break;
966: }
967: }
968:
969: return TRUE;
970: }
971:
972: /*
973: * Wait for data to come in.
974: *
975: * This continues processing until a complete file or command has been
976: * received.
977: */
978:
979: boolean
980: fzwait(qdaemon)
981: struct sdaemon *qdaemon;
982: {
983: int c,cerr,rxcount;
984: boolean fexit;
985: achdrval_t rx_hdr;
986:
987: if (!fzstart_rx ())
988: return FALSE;
989:
990: cerr = cZretries;
991:
992: goto nxthdr;
993:
994: for (;;) {
995: if (!fzsend_hdr (qdaemon, ZHEX, ZRPOS,
996: hvzencode_data_hdr (wpZrxbytes), FALSE))
997: return FALSE;
998: nxthdr:
999: c = izrecv_hdr (qdaemon, rx_hdr);
1000:
1001: switch (c) {
1002: case ZM_TIMEOUT:
1003: case ZNAK:
1004: if (--cerr < 0) {
1005: ulog (LOG_ERROR, "fzwait: retries exhausted");
1006: return FALSE;
1007: }
1008: continue;
1009: case ZM_ERROR:
1010: if (--cerr < 0) {
1011: ulog (LOG_ERROR, "fzwait: retries exhausted");
1012: return FALSE;
1013: }
1014: /*fport_break ();*/
1015: continue;
1016: case ZM_RCDO:
1017: case ZFIN:
1018: return FALSE;
1019: case ZRPOS:
1020: case ZACK:
1021: goto nxthdr; /* ignore, partner is out of sync */
1022: case ZDATA: {
1023: winpos_t rx_bytes;
1024:
1025: zdecode_data_hdr (rclhdr (rx_hdr), &rx_bytes);
1026: DEBUG_MESSAGE2 (DEBUG_PROTO,
1027: "fzwait: bytes(us,them) 0x%lx,0x%lx",
1028: wpZrxbytes, rx_bytes);
1029: if (rx_bytes != wpZrxbytes) {
1030: if (--cerr < 0) {
1031: ulog (LOG_ERROR,
1032: "fzwait: retries exhausted");
1033: return FALSE;
1034: }
1035: (void) zrdat32 (qdaemon, zZrx_packet_buf,
1036: 1024, &rxcount);
1037: /*fport_break ();*/
1038: /*
1039: * FIXME: Seems to me we should ignore this one
1040: * and go for a timeout, the theory being
1041: * that the appropriate ZRPOS has already
1042: * been sent. We're obviously out of sync.
1043: * /dje 92Mar10
1044: */
1045: continue; /* goto nxthdr? */
1046: }
1047: moredata:
1048: /*
1049: * Do not call fgot_data() with (rxcount == 0) if it's
1050: * not ZCRCF. fgot_data() will erroneously think this
1051: * is the end of the message.
1052: */
1053: c = zrdat32 (qdaemon, zZrx_packet_buf, 1024,
1054: &rxcount);
1055: #if DEBUG > 1
1056: if (FDEBUGGING(DEBUG_PROTO)) {
1057: const char *msg;
1058:
1059: if (c < 0) {
1060: msg = ZZHEADER_NAME(c);
1061: } else {
1062: switch (c) {
1063: case GOTCRCW: msg = "ZCRCW"; break;
1064: case GOTCRCG: msg = "ZCRCG"; break;
1065: case GOTCRCQ: msg = "ZCRCQ"; break;
1066: case GOTCRCE: msg = "ZCRCE"; break;
1067: case GOTCRCF: msg = "ZCRCF"; break;
1068: default : msg = NULL; break;
1069: }
1070: }
1071: if (msg != NULL)
1072: DEBUG_MESSAGE2 (DEBUG_PROTO,
1073: "fzwait: zrdat32: %s, %d bytes",
1074: msg, rxcount);
1075: else
1076: DEBUG_MESSAGE2 (DEBUG_PROTO,
1077: "fzwait: zrdat32: %d, %d bytes",
1078: c, rxcount);
1079: }
1080: #endif
1081: switch (c) {
1082: case ZM_ERROR: /* CRC error */
1083: cZerrors++;
1084: if (--cerr < 0) {
1085: ulog (LOG_ERROR,
1086: "fzwait: retries exhausted");
1087: return FALSE;
1088: }
1089: /*fport_break ();*/
1090: continue;
1091: case ZM_TIMEOUT:
1092: cZtimeouts++;
1093: if (--cerr < 0) {
1094: ulog (LOG_ERROR,
1095: "fzwait: retries exhausted");
1096: return FALSE;
1097: }
1098: continue;
1099: case ZM_RCDO:
1100: return FALSE;
1101: case GOTCRCW:
1102: iZlast_rx_data_packet = ZCRCW;
1103: cerr = cZretries;
1104: if (rxcount != 0
1105: && !fgot_data (qdaemon, zZrx_packet_buf,
1106: (size_t) rxcount,
1107: (const char *) NULL,
1108: (size_t) 0,
1109: -1, -1, (long) -1,
1110: TRUE, &fexit))
1111: return FALSE;
1112: wpZrxbytes += rxcount;
1113: if (!fzsend_hdr (qdaemon, ZHEX, ZACK,
1114: hvzencode_data_hdr (wpZrxbytes),
1115: FALSE))
1116: return FALSE;
1117: if (! fsend_data (qdaemon->qconn, &xon,
1118: (size_t) 1, FALSE))
1119: return FALSE;
1120: goto nxthdr;
1121: case GOTCRCQ:
1122: iZlast_rx_data_packet = ZCRCQ;
1123: cerr = cZretries;
1124: if (rxcount != 0
1125: && !fgot_data (qdaemon, zZrx_packet_buf,
1126: (size_t) rxcount,
1127: (const char *) NULL,
1128: (size_t) 0,
1129: -1, -1, (long) -1,
1130: TRUE, &fexit))
1131: return FALSE;
1132: wpZrxbytes += rxcount;
1133: if (!fzsend_hdr (qdaemon, ZHEX, ZACK,
1134: hvzencode_data_hdr (wpZrxbytes),
1135: FALSE))
1136: return FALSE;
1137: goto moredata;
1138: case GOTCRCG:
1139: iZlast_rx_data_packet = ZCRCG;
1140: cerr = cZretries;
1141: if (rxcount != 0
1142: && !fgot_data (qdaemon, zZrx_packet_buf,
1143: (size_t) rxcount,
1144: (const char *) NULL,
1145: (size_t) 0,
1146: -1, -1, (long) -1,
1147: TRUE, &fexit))
1148: return FALSE;
1149: wpZrxbytes += rxcount;
1150: goto moredata;
1151: case GOTCRCE:
1152: iZlast_rx_data_packet = ZCRCE;
1153: cerr = cZretries;
1154: if (rxcount != 0
1155: && !fgot_data (qdaemon, zZrx_packet_buf,
1156: (size_t) rxcount,
1157: (const char *) NULL,
1158: (size_t) 0,
1159: -1, -1, (long) -1,
1160: TRUE, &fexit))
1161: return FALSE;
1162: wpZrxbytes += rxcount;
1163: goto nxthdr;
1164: case GOTCRCF:
1165: iZlast_rx_data_packet = ZCRCF;
1166: /*
1167: * fzfinish_rx() must be called before
1168: * fgot_data() because fgot_data() will send
1169: * out a UUCP-command but the sender won't be
1170: * ready for it until it receives our final
1171: * ZACK.
1172: */
1173: cerr = cZretries;
1174: wpZrxbytes += rxcount;
1175: if (!fzfinish_rx (qdaemon))
1176: return FALSE;
1177: if (!fgot_data (qdaemon, zZrx_packet_buf,
1178: (size_t) rxcount,
1179: (const char *) NULL,
1180: (size_t) 0, -1, -1,
1181: (long) -1, TRUE, &fexit))
1182: return FALSE;
1183: /*
1184: * FIXME: Examine <fexit>?
1185: * Or maybe ensure it's TRUE?
1186: */
1187: return TRUE;
1188: }
1189: return FALSE;
1190: }
1191: default:
1192: ulog (LOG_FATAL, "fzwait: received header %s",
1193: ZZHEADER_NAME(c));
1194: return FALSE;
1195: }
1196: }
1197:
1198: return TRUE;
1199: }
1200:
1201: /*
1202: * File level routine. Called when initiating/terminating file transfers.
1203: *
1204: * When starting to send a file: (TRUE, TRUE, cbytes)
1205: * When starting to receive a file: (TRUE, FALSE, -1)
1206: * When send EOF, check resend: (FALSE, TRUE, -1)
1207: * When receive EOF, check re-receive: (FALSE, FALSE, -1)
1208: */
1209:
1210: boolean
1211: fzfile(qdaemon, qtrans, fstart, fsend, cbytes, pfhandled)
1212: struct sdaemon *qdaemon;
1213: struct stransfer *qtrans;
1214: boolean fstart;
1215: boolean fsend;
1216: long cbytes;
1217: boolean *pfhandled;
1218: {
1219: long iredo;
1220:
1221: *pfhandled = FALSE;
1222:
1223: DEBUG_MESSAGE2 (DEBUG_PROTO, "fzfile: fstart=%d, fsend=%d", fstart,
1224: fsend);
1225:
1226: if (fsend) {
1227: if (fstart)
1228: return fzstart_tx ();
1229: if (! fzfinish_tx (qdaemon, &iredo))
1230: return FALSE;
1231: if (iredo >= 0) {
1232: if (! ffileisopen (qtrans->e)) {
1233: ulog (LOG_ERROR,
1234: "Attempt to back up non-file");
1235: return FALSE;
1236: }
1237: if (! ffileseek (qtrans->e, iredo)) {
1238: ulog (LOG_ERROR,
1239: "seek: %s", strerror (errno));
1240: return FALSE;
1241: }
1242: *pfhandled = TRUE;
1243: qtrans->fsendfile = TRUE;
1244: return fqueue_send (qdaemon, qtrans);
1245: }
1246: }
1247:
1248: return TRUE;
1249: }
1250:
1251: /****************************************************************************/
1252:
1253:
1254: #if 0 /* not used, we only use 32 bit crc's */
1255: /*
1256: * crctab calculated by Mark G. Mendel, Network Systems Corporation
1257: */
1258:
1259: static unsigned short crctab[256] = {
1260: 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
1261: 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
1262: 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
1263: 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
1264: 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
1265: 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
1266: 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
1267: 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
1268: 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
1269: 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
1270: 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
1271: 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
1272: 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
1273: 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
1274: 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
1275: 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
1276: 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
1277: 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
1278: 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
1279: 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
1280: 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
1281: 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
1282: 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
1283: 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
1284: 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
1285: 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
1286: 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
1287: 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
1288: 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
1289: 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
1290: 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
1291: 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
1292: };
1293: #endif /* crctab */
1294:
1295: /*
1296: * Copyright (C) 1986 Gary S. Brown. You may use this program, or
1297: * code or tables extracted from it, as desired without restriction.
1298: */
1299:
1300: /* First, the polynomial itself and its table of feedback terms. The */
1301: /* polynomial is */
1302: /* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
1303: /* Note that we take it "backwards" and put the highest-order term in */
1304: /* the lowest-order bit. The X^32 term is "implied"; the LSB is the */
1305: /* X^31 term, etc. The X^0 term (usually shown as "+1") results in */
1306: /* the MSB being 1. */
1307:
1308: /* Note that the usual hardware shift register implementation, which */
1309: /* is what we're using (we're merely optimizing it by doing eight-bit */
1310: /* chunks at a time) shifts bits into the lowest-order term. In our */
1311: /* implementation, that means shifting towards the right. Why do we */
1312: /* do it this way? Because the calculated CRC must be transmitted in */
1313: /* order from highest-order term to lowest-order term. UARTs transmit */
1314: /* characters in order from LSB to MSB. By storing the CRC this way, */
1315: /* we hand it to the UART in the order low-byte to high-byte; the UART */
1316: /* sends each low-bit to hight-bit; and the result is transmission bit */
1317: /* by bit from highest- to lowest-order term without requiring any bit */
1318: /* shuffling on our part. Reception works similarly. */
1319:
1320: /* The feedback terms table consists of 256, 32-bit entries. Notes: */
1321: /* */
1322: /* The table can be generated at runtime if desired; code to do so */
1323: /* is shown later. It might not be obvious, but the feedback */
1324: /* terms simply represent the results of eight shift/xor opera- */
1325: /* tions for all combinations of data and CRC register values. */
1326: /* */
1327: /* The values must be right-shifted by eight bits by the "updcrc" */
1328: /* logic; the shift must be unsigned (bring in zeroes). On some */
1329: /* hardware you could probably optimize the shift in assembler by */
1330: /* using byte-swap instructions. */
1331:
1332: static unsigned long crc_32_tab[] = { /* CRC polynomial 0xedb88320 */
1333: 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL,
1334: 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L,
1335: 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L,
1336: 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L,
1337: 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
1338: 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L,
1339: 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL,
1340: 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L,
1341: 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L,
1342: 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
1343: 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L,
1344: 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L,
1345: 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L,
1346: 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL,
1347: 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
1348: 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL,
1349: 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL,
1350: 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L,
1351: 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L,
1352: 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
1353: 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL,
1354: 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L,
1355: 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL,
1356: 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L,
1357: 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
1358: 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL,
1359: 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L,
1360: 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L,
1361: 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L,
1362: 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
1363: 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L,
1364: 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL,
1365: 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL,
1366: 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L,
1367: 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
1368: 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L,
1369: 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL,
1370: 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L,
1371: 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL,
1372: 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
1373: 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L,
1374: 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL,
1375: 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L,
1376: 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L,
1377: 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
1378: 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL,
1379: 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L,
1380: 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL,
1381: 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL,
1382: 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
1383: 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L,
1384: 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L,
1385: 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL,
1386: 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L,
1387: 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
1388: 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L,
1389: 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L,
1390: 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL,
1391: 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L,
1392: 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
1393: 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L,
1394: 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL,
1395: 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L,
1396: 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL
1397: };
1398:
1399: /*
1400: * updcrc macro derived from article Copyright (C) 1986 Stephen Satchell.
1401: * NOTE: First argument must be in range 0 to 255.
1402: * Second argument is referenced twice.
1403: *
1404: * Programmers may incorporate any or all code into their programs,
1405: * giving proper credit within the source. Publication of the
1406: * source routines is permitted so long as proper credit is given
1407: * to Stephen Satchell, Satchell Evaluations and Chuck Forsberg,
1408: * Omen Technology.
1409: */
1410:
1411: #define updcrc(cp, crc) (crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp)
1412:
1413: #define UPDC32(b, crc) \
1414: (crc_32_tab[((unsigned)(crc) ^ (unsigned)(b)) & 0xff] \
1415: ^ (((crc) >> 8) & 0x00ffffffL))
1416:
1417: /****************************************************************************/
1418:
1419: /*
1420: * This section contains the guts of the Zmodem protocol. The intention
1421: * is to leave as much of it alone as possible at the start. Overtime it
1422: * will be cleaned up (EG: I'd like to clean up the naming of the globals).
1423: * Also, Zmodem has a different coding style. Over time this will be converted
1424: * to the Taylor UUCP coding style.
1425: */
1426:
1427: /*
1428: * Start the protocol (exchange init packets) ...
1429: *
1430: * UUCP can transfer files in both directions in one session. Therefore the
1431: * init sequence is a little different.
1432: *
1433: * 1) ZINIT packets are exchanged
1434: * - contains protocol version and protocol flags
1435: * 2) ZDATA packets are exchanged
1436: * - is intended to contain various numeric and string information
1437: * 3) ZACK packets are exchanged
1438: * 4) ZINITEND packets are exchanged
1439: */
1440:
1441: static boolean
1442: fzstart_proto(qdaemon)
1443: struct sdaemon *qdaemon;
1444: {
1445: int i;
1446: achdrval_t tx_hdr,rx_hdr;
1447:
1448: for (i = 0; i < cZstartup_retries; i++) {
1449: stohdr (0L, tx_hdr);
1450: tx_hdr[ZF0] = ZPROTOCOL_VERSION;
1451: if (fZesc_ctl)
1452: tx_hdr[ZF1] |= TX_ESCCTL;
1453: switch (izexchange_init (qdaemon, ZINIT, tx_hdr, rx_hdr)) {
1454: case -1: return FALSE;
1455: case 0: continue;
1456: case 1: break;
1457: }
1458: #if 0 /* can't work, but kept for documentation */
1459: if (rx_hdr[ZF0] == 0) {
1460: ulog (LOG_ERROR, "Old protocol version, init failed");
1461: return FALSE;
1462: }
1463: #endif
1464: fZesc_ctl = fZesc_ctl || (rx_hdr[ZF1] & TX_ESCCTL) != 0;
1465:
1466: stohdr (0L, tx_hdr);
1467: switch (izexchange_init (qdaemon, ZDATA, tx_hdr, rx_hdr)) {
1468: case -1: return FALSE;
1469: case 0: continue;
1470: case 1: break;
1471: }
1472:
1473: stohdr (0L, tx_hdr);
1474: switch (izexchange_init (qdaemon, ZACK, tx_hdr, rx_hdr)) {
1475: case -1: return FALSE;
1476: case 0: continue;
1477: case 1: break;
1478: }
1479:
1480: stohdr (0L, tx_hdr);
1481: switch (izexchange_init (qdaemon, ZINITEND, tx_hdr, rx_hdr)) {
1482: case -1: return FALSE;
1483: case 0: continue;
1484: case 1: break;
1485: }
1486:
1487: DEBUG_MESSAGE0 (DEBUG_PROTO,
1488: "fzstart_proto: Protocol started");
1489: return TRUE;
1490:
1491: /* FIXME: see protg.c regarding sequencing here. */
1492: }
1493:
1494: ulog (LOG_ERROR, "Protocol init failed");
1495: return FALSE;
1496: }
1497:
1498: /*
1499: * Exchange init messages. This is based on 'g'.
1500: * See the comments concerning fgexchange_init() in protg.c.
1501: *
1502: * We return 1 for success, 0 for restart, -1 for comm failure (terminate).
1503: */
1504:
1505: static int
1506: izexchange_init(qdaemon, send_type, send_val, recv_val)
1507: struct sdaemon *qdaemon;
1508: int send_type;
1509: achdrval_t send_val;
1510: achdrval_t recv_val;
1511: {
1512: int i,recv_type,count;
1513:
1514: for (i = 0; i < CEXCHANGE_INIT_RETRIES; i++) {
1515: if (!fzsend_hdr (qdaemon, send_type == ZDATA ? ZBIN : ZHEX,
1516: send_type, rclhdr (send_val), FALSE))
1517: return -1;
1518:
1519: /*
1520: * The ZDATA packet is intended to contain the <Attn> string
1521: * (eventually, if it's ever usable) and allow for anything
1522: * else that will need to be thrown in.
1523: */
1524:
1525: if (send_type == ZDATA) {
1526: count = czbuild_data_packet (zZtx_packet_buf, "",
1527: (size_t) 1, ZCRCF);
1528: if (!fsend_data (qdaemon->qconn, zZtx_packet_buf,
1529: (size_t) count, FALSE))
1530: return -1;
1531: }
1532:
1533: recv_type = izrecv_hdr (qdaemon, recv_val);
1534:
1535: switch (recv_type) {
1536: case ZM_TIMEOUT:
1537: case ZM_ERROR:
1538: continue;
1539: case ZM_RCDO:
1540: case ZFIN:
1541: return -1;
1542: case ZINIT:
1543: case ZACK:
1544: case ZINITEND:
1545: break;
1546: case ZDATA:
1547: if (zrdat32 (qdaemon, zZrx_packet_buf, 1024, &count)
1548: == GOTCRCF)
1549: break;
1550: continue;
1551: default:
1552: continue;
1553: }
1554:
1555: if (recv_type == send_type)
1556: return 1;
1557:
1558: /*
1559: * If the other side is farther along than we are, we have lost
1560: * a packet. Fall immediately back to ZINIT (but don't fail
1561: * if we are already doing ZINIT, since that would count
1562: * against cStart_retries more than it should).
1563: *
1564: * FIXME: The ">" test is "<" in protg.c. Check who's right.
1565: */
1566:
1567: if (recv_type > send_type && send_type != ZINIT)
1568: return 0;
1569:
1570: /*
1571: * If we are sending ZINITEND and we receive an ZINIT, the
1572: * other side has falled back (we know this because we have
1573: * seen a ZINIT from them). Fall back ourselves to start
1574: * the whole handshake over again.
1575: */
1576:
1577: if (recv_type == ZINIT && send_type == ZINITEND)
1578: return 0;
1579: }
1580:
1581: return 0;
1582: }
1583:
1584: /*
1585: * Shut down the protocol ...
1586: */
1587:
1588: static boolean
1589: fzshutdown_proto(qdaemon)
1590: struct sdaemon *qdaemon;
1591: {
1592: (void) fzsend_hdr (qdaemon, ZHEX, ZFIN, 0L, FALSE);
1593: return TRUE;
1594: }
1595:
1596: /*
1597: * Reset the transmitter side for sending a new message ...
1598: */
1599:
1600: static boolean
1601: fzstart_tx()
1602: {
1603: iZlast_tx_data_packet = -1;
1604:
1605: /*
1606: * <wpZlastsync> is set to -1L to suppress ZCRCW request otherwise
1607: * triggered by (wpZlastsync == wpZtxpos).
1608: */
1609:
1610: cZblklen = 1024;
1611: wpZlastsync = -1L;
1612: iZbeenhereb4 = 0;
1613: iZtleft = 0;
1614: iZjunk_count = 0;
1615:
1616: wpZtxpos = (wpZtxpos + 1024L) & ~1023L; /* next packet boundary */
1617: wpZlrxpos = wpZrxpos = wpZtxpos;
1618:
1619: wpZtxstart = wpZtxpos; /* so we can compute the "file offset" */
1620:
1621: return TRUE;
1622: }
1623:
1624: /*
1625: * Finish the sending of a message ...
1626: *
1627: * Basically, we wait for some indication that the receiver received our last
1628: * message. If the receiver tells us to restart from some point, we set
1629: * *plredo to that point.
1630: *
1631: * FIXME: This function is a major kludge at the moment. It is taken from
1632: * getinsync(). It is necessary because I don't yet buffer outgoing data.
1633: * It will go away when we do (buffer outgoing data).
1634: */
1635:
1636: static boolean
1637: fzfinish_tx(qdaemon, plredo)
1638: struct sdaemon *qdaemon;
1639: long *plredo;
1640: {
1641: int c,cerr,ctimeouts;
1642: achdrval_t rx_hdr;
1643: winpos_t rx_bytes;
1644:
1645: *plredo = -1;
1646: cerr = cZretries;
1647: ctimeouts = 0;
1648:
1649: DEBUG_MESSAGE4 (DEBUG_PROTO,
1650: "fzfinish_tx: txpos=0x%lx, rxpos=0x%lx, lrxpos=0x%lx, rxbytes=0x%lx",
1651: wpZtxpos, wpZrxpos, wpZlrxpos, wpZrxbytes);
1652:
1653: for (;;) {
1654: c = izrecv_hdr (qdaemon, rx_hdr);
1655:
1656: switch (c) {
1657: case ZRPOS:
1658: wpZrxpos = lzupdate_rxpos (rx_hdr, wpZrxpos,
1659: wpZlrxpos, wpZtxpos);
1660: /*
1661: * If the receiver sends a ZRPOS for the 1k block after
1662: * the one we're currently at, we lost the final ZACK.
1663: * We cheat and ignore this ZRPOS. Remember: the theory
1664: * is that this entire function will go away when we
1665: * begin buffering the outgoing data. Of course, one
1666: * can reword the protocol definition and say this
1667: * isn't cheating at all.
1668: */
1669: if (((wpZtxpos + 1024) & ~1023) == wpZrxpos)
1670: return TRUE;
1671: cZbytes_resent += wpZtxpos - wpZrxpos;
1672: wpZlrxpos = wpZtxpos = wpZrxpos;
1673: if (wpZlastsync == wpZrxpos) {
1674: if (++iZbeenhereb4 > 4)
1675: if (cZblklen > 32)
1676: cZblklen /= 2;
1677: /* FIXME: shouldn't we reset iZbeenhereb4? */
1678: }
1679: wpZlastsync = wpZrxpos;
1680: iZlast_tx_data_packet = ZCRCW; /* force a timeout */
1681: *plredo = wpZrxpos - wpZtxstart;
1682: return TRUE;
1683: case ZACK:
1684: wpZrxpos = lzupdate_rxpos (rx_hdr, wpZrxpos,
1685: wpZlrxpos, wpZtxpos);
1686: wpZlrxpos = wpZrxpos;
1687: if (wpZtxpos == wpZrxpos) /* the ACK we want? */
1688: return TRUE;
1689: break;
1690: case ZDATA:
1691: /*
1692: * We cheat here and take advantage of UUCP's current
1693: * half duplex nature. If we get a ZDATA starting on
1694: * the next 1k boundary, we lost the ZACK. We cheat and
1695: * tuck it away so that izrecv_hdr() can later detect
1696: * it. Remember: see above.
1697: */
1698: zdecode_data_hdr (rclhdr (rx_hdr), &rx_bytes);
1699: if (((wpZrxbytes + 1024L) & ~1023L) == rx_bytes) {
1700: iZpkt_rcvd_kludge = ZDATA;
1701: hvZpkt_hdrval_kludge = rclhdr (rx_hdr);
1702: return TRUE;
1703: }
1704: break; /* ignore, out of sync (old) */
1705: case ZNAK:
1706: /*
1707: * We cheat here and take advantage of UUCP's current
1708: * half duplex nature. If we get a ZNAK starting on
1709: * the next 1k boundary, we lost the ZACK. We cheat and
1710: * throw the ZNAK away. Remember: see above.
1711: *
1712: * On the other hand, if (rx_bytes == wpZrxbytes) then
1713: * the other side is also in fzfinish_tx(). He must
1714: * have lost our ZACK, so we send him another.
1715: */
1716: zdecode_data_hdr (rclhdr (rx_hdr), &rx_bytes);
1717: if (((wpZrxbytes + 1024L) & ~1023L) == rx_bytes)
1718: return TRUE;
1719: if (rx_bytes == wpZrxbytes) {
1720: if (!fzsend_hdr (qdaemon, ZHEX, ZACK,
1721: hvzencode_data_hdr (wpZrxbytes),
1722: TRUE))
1723: return FALSE;
1724: }
1725: break; /* ignore, out of sync (old) */
1726: case ZFIN:
1727: case ZM_RCDO:
1728: return FALSE;
1729: case ZM_TIMEOUT:
1730: if (--cerr < 0) {
1731: ulog (LOG_ERROR,
1732: "fzfinish_tx: retries exhausted");
1733: return FALSE;
1734: }
1735: /*
1736: * Normally the sender doesn't send NAK's for timeouts.
1737: * We have to here because of the following scenario:
1738: *
1739: * - We send ZDATA/ZCRCF
1740: * - They send ZACK (corrupted)
1741: * - They send ZDATA/ZCRCF (corrupted)
1742: *
1743: * At this point, both sides are in fzfinish_tx().
1744: * We only send ZNAK every second timeout to increase
1745: * our timeout delay vs. our partner. This tries to
1746: * avoid ZRPOS and ZNAK "passing in transit".
1747: */
1748: if (++ctimeouts % 2 == 0)
1749: if (!fzsend_hdr (qdaemon, ZHEX, ZNAK,
1750: hvzencode_data_hdr (wpZtxpos),
1751: TRUE))
1752: return FALSE;
1753: break;
1754: case ZM_ERROR:
1755: default:
1756: if (--cerr < 0) {
1757: ulog (LOG_ERROR,
1758: "fzfinish_tx: retries exhausted");
1759: return FALSE;
1760: }
1761: if (!fzsend_hdr (qdaemon, ZHEX, ZNAK,
1762: hvzencode_data_hdr (wpZtxpos),
1763: TRUE))
1764: return FALSE;
1765: break;
1766: }
1767: }
1768: }
1769:
1770: /*
1771: * Initialize the receiver ...
1772: */
1773:
1774: static boolean
1775: fzstart_rx()
1776: {
1777: wpZrxbytes = (wpZrxbytes + 1024L) & ~1023L; /* next packet boundary */
1778:
1779: return TRUE;
1780: }
1781:
1782: /*
1783: * Terminate the receiver ...
1784: *
1785: * Acknowledge the last packet received.
1786: */
1787:
1788: static boolean
1789: fzfinish_rx(qdaemon)
1790: struct sdaemon *qdaemon;
1791: {
1792: DEBUG_MESSAGE0 (DEBUG_PROTO, "fzfinish_rx: message/file received");
1793:
1794: return fzsend_hdr (qdaemon, ZHEX, ZACK,
1795: hvzencode_data_hdr (wpZrxbytes), FALSE);
1796: }
1797:
1798: /*
1799: * Send a Zmodem header to our partner ...
1800: */
1801:
1802: static boolean
1803: fzsend_hdr(qdaemon, ipkttype, ihdrtype, hdrval, fcheckreceive)
1804: struct sdaemon *qdaemon;
1805: int ipkttype;
1806: int ihdrtype;
1807: hdrval_t hdrval;
1808: boolean fcheckreceive;
1809: {
1810: int cpacketlen;
1811:
1812: DEBUG_MESSAGE2 (DEBUG_PROTO, "fzsend_hdr: %s, data = 0x%lx",
1813: ZZHEADER_NAME(ihdrtype), hdrval);
1814:
1815: cpacketlen = czbuild_header (zZtx_packet_buf, ipkttype,
1816: ihdrtype, hdrval);
1817:
1818: #ifdef DJE_TESTING
1819: #if 0
1820: if (ihdrtype == ZACK && rand () % 100 < uucptest2) {
1821: cZheaders_sent++;
1822: return TRUE;
1823: }
1824: #else
1825: if (ihdrtype == ZACK || ihdrtype == ZDATA) {
1826: boolean fresult;
1827: int old;
1828: extern int uucptest,uucptest2;
1829:
1830: old = uucptest;
1831: uucptest = uucptest2;
1832: cZheaders_sent++;
1833: fresult = fsend_data (qdaemon->qconn, zZtx_packet_buf,
1834: (size_t) cpacketlen, fcheckreceive);
1835: uucptest = old;
1836: return fresult;
1837: }
1838: #endif
1839: #endif
1840: cZheaders_sent++;
1841: return fsend_data (qdaemon->qconn, zZtx_packet_buf,
1842: (size_t) cpacketlen, fcheckreceive);
1843: }
1844:
1845: /*
1846: * Send a data packet to our partner ...
1847: * <frameend> is one of ZCRCx.
1848: */
1849:
1850: static boolean
1851: fzsend_data_packet(qdaemon, zdata, cdata, frameend, fcheckreceive)
1852: struct sdaemon *qdaemon;
1853: char *zdata;
1854: size_t cdata;
1855: int frameend;
1856: boolean fcheckreceive;
1857: {
1858: int cpacketlen;
1859:
1860: cpacketlen = czbuild_data_packet (zZtx_packet_buf, zdata, cdata,
1861: frameend);
1862:
1863: return fsend_data (qdaemon->qconn, zZtx_packet_buf,
1864: (size_t) cpacketlen, fcheckreceive);
1865: }
1866:
1867: /*
1868: * Build Zmodem headers ...
1869: *
1870: * Note that we use 32 bit CRC's for ZHEX headers.
1871: *
1872: * This function is a combination of zm fns: zsbhdr(), zsbh32(), and zshhdr().
1873: */
1874:
1875: static int
1876: czbuild_header(zresult, ipkttype, ihdrtype, hdrval)
1877: char *zresult;
1878: int ipkttype;
1879: int ihdrtype;
1880: hdrval_t hdrval;
1881: {
1882: char *p;
1883: int i;
1884: unsigned long crc;
1885: achdrval_t achdrval;
1886:
1887: p = zresult;
1888:
1889: switch (ipkttype) {
1890: case ZBIN:
1891: *p++ = ZPAD;
1892: *p++ = ZDLE;
1893: *p++ = ZBIN;
1894: p = zputchar (p, ihdrtype);
1895: crc = ICRCINIT;
1896: crc = UPDC32 (ihdrtype, crc);
1897: stohdr (hdrval, achdrval);
1898: for (i = 0; i < 4; i++) {
1899: p = zputchar (p, achdrval[i]);
1900: crc = UPDC32 (achdrval[i], crc);
1901: }
1902: crc = ~crc;
1903: for (i = 0; i < 4; i++) {
1904: p = zputchar (p, (char) crc);
1905: crc >>= 8;
1906: }
1907: break;
1908: case ZHEX: /* build hex header */
1909: *p++ = ZPAD;
1910: *p++ = ZPAD;
1911: *p++ = ZDLE;
1912: *p++ = ZHEX;
1913: p = zputhex (p, ihdrtype);
1914: crc = ICRCINIT;
1915: crc = UPDC32 (ihdrtype, crc);
1916: stohdr (hdrval, achdrval);
1917: for (i = 0; i < 4; i++) {
1918: p = zputhex (p, achdrval[i]);
1919: crc = UPDC32 (achdrval[i], crc);
1920: }
1921: crc = ~crc;
1922: for (i = 0; i < 4; i++) {
1923: p = zputhex (p, (char) crc);
1924: crc >>= 8;
1925: }
1926: *p++ = CR;
1927: /*
1928: * Uncork the remote in case a fake XOFF has stopped data flow.
1929: */
1930: if (ihdrtype != ZFIN && ihdrtype != ZACK) /* FIXME: why? */
1931: *p++ = XON;
1932: break;
1933: default:
1934: ulog (LOG_FATAL, "czbuild_header: ipkttype == %d", ipkttype);
1935: break;
1936: }
1937:
1938: return p - zresult;
1939: }
1940:
1941: /*
1942: * Build Zmodem data packets ...
1943: *
1944: * This function is zsdata() and zsda32() from the zm source.
1945: */
1946:
1947: static int
1948: czbuild_data_packet(zresult, zdata, cdata, frameend)
1949: char *zresult;
1950: const char *zdata;
1951: size_t cdata;
1952: int frameend;
1953: {
1954: char *p;
1955: unsigned long crc;
1956:
1957: p = zresult;
1958:
1959: crc = ICRCINIT;
1960: for ( ; cdata-- != 0; zdata++) {
1961: char c;
1962:
1963: c = *zdata;
1964: if (c & 0140)
1965: *p++ = c;
1966: else
1967: p = zputchar (p, c);
1968: crc = UPDC32 ((unsigned char) c, crc);
1969: }
1970: *p++ = ZDLE;
1971: *p++ = frameend;
1972: crc = UPDC32 (frameend, crc);
1973: crc = ~crc;
1974: for (cdata = 0; cdata < 4; cdata++) {
1975: p = zputchar (p, (char) crc);
1976: crc >>= 8;
1977: }
1978: if (frameend == ZCRCW || frameend == ZCRCE || frameend == ZCRCF) {
1979: *p++ = CR;
1980: *p++ = XON;
1981: }
1982:
1983: return p - zresult;
1984: }
1985:
1986: /*
1987: * Read in a header ...
1988: *
1989: * This is function zgethdr() from the Zmodem source.
1990: */
1991:
1992: static int
1993: izrecv_hdr(qdaemon, hdr)
1994: struct sdaemon *qdaemon;
1995: achdrval_t hdr;
1996: {
1997: int c,cerr;
1998:
1999: /*
2000: * Kludge alert! If another part of the program received a packet but
2001: * wasn't ready to handle it, it is tucked away for us to handle now.
2002: */
2003:
2004: if (iZpkt_rcvd_kludge != -1) {
2005: c = iZpkt_rcvd_kludge;
2006: iZpkt_rcvd_kludge = -1;
2007: stohdr (hvZpkt_hdrval_kludge, hdr);
2008: DEBUG_MESSAGE2 (DEBUG_PROTO,
2009: "izrecv_hdr: queued %s, data = 0x%lx",
2010: ZZHEADER_NAME(c), rclhdr (hdr));
2011: cZheaders_received++;
2012: return c;
2013: }
2014:
2015: cerr = cZmax_garbage; /* Max bytes before start of frame */
2016:
2017: again:
2018: switch (c = noxrd7 (qdaemon)) {
2019: case ZM_TIMEOUT:
2020: case ZM_ERROR:
2021: case ZM_RCDO:
2022: goto fifi;
2023: case ZPAD: /* This is what we want */
2024: break;
2025: case CR: /* padding at end of previous header */
2026: default:
2027: if (--cerr < 0) {
2028: c = ZM_ERROR;
2029: goto fifi;
2030: }
2031: goto again;
2032: }
2033:
2034: splat:
2035: switch (c = noxrd7 (qdaemon)) {
2036: case ZPAD:
2037: if (--cerr < 0) {
2038: c = ZM_ERROR;
2039: goto fifi;
2040: }
2041: goto splat;
2042: case ZM_TIMEOUT:
2043: case ZM_RCDO:
2044: goto fifi;
2045: case ZDLE: /* This is what we want */
2046: break;
2047: default:
2048: if (--cerr < 0) {
2049: c = ZM_ERROR;
2050: goto fifi;
2051: }
2052: goto again;
2053: }
2054:
2055: switch (c = noxrd7 (qdaemon)) {
2056: case ZM_TIMEOUT:
2057: case ZM_RCDO:
2058: goto fifi;
2059: case ZBIN:
2060: c = zrbhdr32 (qdaemon, hdr);
2061: break;
2062: case ZHEX:
2063: c = zrhhdr (qdaemon, hdr);
2064: break;
2065: default:
2066: if (--cerr < 0) {
2067: c = ZM_ERROR;
2068: goto fifi;
2069: }
2070: goto again;
2071: }
2072:
2073: fifi:
2074: switch (c) {
2075: case ZM_TIMEOUT:
2076: cZtimeouts++;
2077: break;
2078: case ZM_ERROR:
2079: cZerrors++;
2080: break;
2081: case ZM_RCDO:
2082: break;
2083: default:
2084: cZheaders_received++;
2085: break;
2086: }
2087: DEBUG_MESSAGE2 (DEBUG_PROTO, "izrecv_hdr: %s, data = 0x%x",
2088: ZZHEADER_NAME(c), rclhdr (hdr));
2089:
2090: return c;
2091: }
2092:
2093: /*
2094: * Receive a binary style header (type and position) with 32 bit FCS ...
2095: */
2096:
2097: static int
2098: zrbhdr32(qdaemon, hdr)
2099: struct sdaemon *qdaemon;
2100: achdrval_t hdr;
2101: {
2102: int c,i,type;
2103: unsigned long crc;
2104:
2105: if ((c = zdlread (qdaemon)) & ~0377)
2106: return c;
2107: type = c;
2108: crc = ICRCINIT;
2109: crc = UPDC32 (c, crc);
2110:
2111: for (i = 0; i < 4; i++) {
2112: if ((c = zdlread (qdaemon)) & ~0377)
2113: return c;
2114: crc = UPDC32 (c, crc);
2115: hdr[i] = (char) c;
2116: }
2117: for (i = 0; i < 4; i++) {
2118: if ((c = zdlread (qdaemon)) & ~0377)
2119: return c;
2120: crc = UPDC32 (c, crc);
2121: }
2122: if (crc != IHDRCRC)
2123: return ZM_ERROR;
2124:
2125: return type;
2126: }
2127:
2128: /*
2129: * Receive a hex style header (type and position) ...
2130: */
2131:
2132: static int
2133: zrhhdr(qdaemon, hdr)
2134: struct sdaemon *qdaemon;
2135: achdrval_t hdr;
2136: {
2137: int c,i,type;
2138: unsigned long crc;
2139:
2140: if ((c = zgethex (qdaemon)) < 0)
2141: return c;
2142: type = c;
2143: crc = ICRCINIT;
2144: crc = UPDC32 (c, crc);
2145:
2146: for (i = 0; i < 4; i++) {
2147: if ((c = zgethex (qdaemon)) < 0)
2148: return c;
2149: crc = UPDC32 (c, crc);
2150: hdr[i] = (char) c;
2151: }
2152: for (i = 0; i < 4; i++) {
2153: if ((c = zgethex (qdaemon)) < 0)
2154: return c;
2155: crc = UPDC32 (c, crc);
2156: }
2157: if (crc != IHDRCRC)
2158: return ZM_ERROR;
2159:
2160: return type;
2161: }
2162:
2163: /*
2164: * Receive a data packet ...
2165: */
2166:
2167: static int
2168: zrdat32(qdaemon, buf, length, iprxcount)
2169: struct sdaemon *qdaemon;
2170: char *buf;
2171: int length;
2172: int *iprxcount;
2173: {
2174: int c,d;
2175: unsigned long crc;
2176: char *end;
2177:
2178: crc = ICRCINIT;
2179: *iprxcount = 0;
2180: end = buf + length;
2181: while (buf <= end) {
2182: if ((c = zdlread (qdaemon)) & ~0377) {
2183: crcfoo:
2184: switch (c) {
2185: case GOTCRCE:
2186: case GOTCRCG:
2187: case GOTCRCQ:
2188: case GOTCRCW:
2189: case GOTCRCF:
2190: d = c;
2191: c &= 0377;
2192: crc = UPDC32 (c, crc);
2193: if ((c = zdlread (qdaemon)) & ~0377)
2194: goto crcfoo;
2195: crc = UPDC32 (c, crc);
2196: if ((c = zdlread (qdaemon)) & ~0377)
2197: goto crcfoo;
2198: crc = UPDC32 (c, crc);
2199: if ((c = zdlread (qdaemon)) & ~0377)
2200: goto crcfoo;
2201: crc = UPDC32 (c, crc);
2202: if ((c = zdlread (qdaemon)) & ~0377)
2203: goto crcfoo;
2204: crc = UPDC32 (c, crc);
2205: if (crc != IHDRCRC)
2206: return ZM_ERROR;
2207: *iprxcount = length - (end - buf);
2208: return d;
2209: case ZM_TIMEOUT:
2210: case ZM_RCDO:
2211: return c;
2212: default:
2213: return ZM_ERROR;
2214: }
2215: }
2216: *buf++ = (char) c;
2217: crc = UPDC32 (c, crc);
2218: }
2219:
2220: return ZM_ERROR; /* bad packet, too long */
2221: }
2222:
2223: /*
2224: * Respond to receiver's complaint, get back in sync with receiver ...
2225: */
2226:
2227: static int
2228: getinsync(qdaemon, flag)
2229: struct sdaemon *qdaemon;
2230: boolean flag;
2231: {
2232: int c,cerr;
2233: achdrval_t rx_hdr;
2234:
2235: cerr = cZretries;
2236:
2237: for (;;) {
2238: c = izrecv_hdr (qdaemon, rx_hdr);
2239:
2240: switch (c) {
2241: case ZRPOS:
2242: wpZrxpos = lzupdate_rxpos (rx_hdr, wpZrxpos,
2243: wpZlrxpos, wpZtxpos);
2244: cZbytes_resent += wpZtxpos - wpZrxpos;
2245: wpZlrxpos = wpZtxpos = wpZrxpos;
2246: if (wpZlastsync == wpZrxpos) {
2247: if (++iZbeenhereb4 > 4)
2248: if (cZblklen > 32)
2249: cZblklen /= 2;
2250: /* FIXME: shouldn't we reset iZbeenhereb4? */
2251: }
2252: wpZlastsync = wpZrxpos;
2253: return ZRPOS;
2254: case ZACK:
2255: wpZrxpos = lzupdate_rxpos (rx_hdr, wpZrxpos,
2256: wpZlrxpos, wpZtxpos);
2257: wpZlrxpos = wpZrxpos;
2258: if (flag || wpZtxpos == wpZrxpos)
2259: return ZACK;
2260: break;
2261: case ZNAK: {
2262: winpos_t rx_bytes;
2263: /*
2264: * Our partner is in fzfinish_tx() and is waiting
2265: * for ZACK ...
2266: */
2267: zdecode_data_hdr (rclhdr (rx_hdr), &rx_bytes);
2268: if (rx_bytes == wpZrxbytes) {
2269: if (!fzsend_hdr (qdaemon, ZHEX, ZACK,
2270: hvzencode_data_hdr (wpZrxbytes),
2271: TRUE))
2272: return FALSE;
2273: }
2274: break;
2275: }
2276: case ZFIN:
2277: case ZM_RCDO:
2278: return c;
2279: case ZM_TIMEOUT:
2280: if (--cerr < 0) {
2281: ulog (LOG_ERROR,
2282: "getinsync: retries exhausted");
2283: return ZM_ERROR;
2284: }
2285: break; /* sender doesn't send ZNAK for timeout */
2286: case ZM_ERROR:
2287: default:
2288: if (--cerr < 0) {
2289: ulog (LOG_ERROR,
2290: "getinsync: retries exhausted");
2291: return ZM_ERROR;
2292: }
2293: if (!fzsend_hdr (qdaemon, ZHEX, ZNAK,
2294: hvzencode_data_hdr (wpZtxpos),
2295: TRUE))
2296: return ZM_ERROR;
2297: break;
2298: }
2299: }
2300: }
2301:
2302: /*
2303: * Send a byte as two hex digits ...
2304: */
2305:
2306: static char *
2307: zputhex(p, ch)
2308: char *p;
2309: int ch;
2310: {
2311: static char digits[] = "0123456789abcdef";
2312:
2313: *p++ = digits[(ch & 0xF0) >> 4];
2314: *p++ = digits[ch & 0xF];
2315: return p;
2316: }
2317:
2318: /*
2319: * Send character c with ZMODEM escape sequence encoding ...
2320: *
2321: * Escape XON, XOFF.
2322: * FIXME: Escape CR following @ (Telenet net escape) ... disabled for now
2323: * Will need to put back references to <lastsent>.
2324: */
2325:
2326: static char *
2327: zputchar(p, ch)
2328: char *p;
2329: int ch;
2330: {
2331: char c = ch;
2332:
2333: /* Quick check for non control characters */
2334:
2335: if (c & 0140) {
2336: *p++ = c;
2337: } else {
2338: switch (c & 0377) {
2339: case ZDLE:
2340: *p++ = ZDLE;
2341: *p++ = c ^ 0100;
2342: break;
2343: case CR:
2344: #if 0
2345: if (!fZesc_ctl && (lastsent & 0177) != '@')
2346: goto sendit;
2347: #endif
2348: /* fall through */
2349: case 020: /* ^P */
2350: case XON:
2351: case XOFF:
2352: *p++ = ZDLE;
2353: c ^= 0100;
2354: /*sendit:*/
2355: *p++ = c;
2356: break;
2357: default:
2358: if (fZesc_ctl && !(c & 0140)) {
2359: *p++ = ZDLE;
2360: c ^= 0100;
2361: }
2362: *p++ = c;
2363: break;
2364: }
2365: }
2366:
2367: return p;
2368: }
2369:
2370: /*
2371: * Decode two lower case hex digits into an 8 bit byte value ...
2372: */
2373:
2374: static int
2375: zgethex(qdaemon)
2376: struct sdaemon *qdaemon;
2377: {
2378: int c,n;
2379:
2380: if ((c = noxrd7 (qdaemon)) < 0)
2381: return c;
2382: n = c - '0';
2383: if (n > 9)
2384: n -= ('a' - ':');
2385: if (n & ~0xF)
2386: return ZM_ERROR;
2387: if ((c = noxrd7 (qdaemon)) < 0)
2388: return c;
2389: c -= '0';
2390: if (c > 9)
2391: c -= ('a' - ':');
2392: if (c & ~0xF)
2393: return ZM_ERROR;
2394: c += (n << 4);
2395:
2396: return c;
2397: }
2398:
2399: /*
2400: * Read a byte, checking for ZMODEM escape encoding ...
2401: */
2402:
2403: static int
2404: zdlread(qdaemon)
2405: struct sdaemon *qdaemon;
2406: {
2407: int c;
2408:
2409: again:
2410: READCHAR (qdaemon, c, cZtimeout);
2411: if (c < 0)
2412: return c;
2413: if (c & 0140) /* quick check for non control characters */
2414: return c;
2415: switch (c) {
2416: case ZDLE:
2417: break;
2418: case XON:
2419: goto again;
2420: case XOFF:
2421: READCHAR (qdaemon, c, XON_WAIT);
2422: goto again;
2423: default:
2424: if (fZesc_ctl && !(c & 0140))
2425: goto again;
2426: return c;
2427: }
2428:
2429: again2:
2430: READCHAR (qdaemon, c, cZtimeout);
2431: if (c < 0)
2432: return c;
2433: switch (c) {
2434: case ZCRCE:
2435: case ZCRCG:
2436: case ZCRCQ:
2437: case ZCRCW:
2438: case ZCRCF:
2439: return c | GOTOR;
2440: case ZRUB0: /* FIXME: This is never generated. */
2441: return 0177;
2442: case ZRUB1: /* FIXME: This is never generated. */
2443: return 0377;
2444: case XON:
2445: goto again2;
2446: case XOFF:
2447: READCHAR (qdaemon, c, XON_WAIT);
2448: goto again2;
2449: default:
2450: if (fZesc_ctl && !(c & 0140))
2451: goto again2; /* FIXME: why again2? */
2452: if ((c & 0140) == 0100)
2453: return c ^ 0100;
2454: break;
2455: }
2456:
2457: return ZM_ERROR;
2458: }
2459:
2460: /*
2461: * Read a character from the modem line with timeout ...
2462: * Eat parity bit, XON and XOFF characters.
2463: */
2464:
2465: static int
2466: noxrd7(qdaemon)
2467: struct sdaemon *qdaemon;
2468: {
2469: int c;
2470:
2471: for (;;) {
2472: READCHAR (qdaemon, c, cZtimeout);
2473: if (c < 0)
2474: return c;
2475: switch (c &= 0177) {
2476: case XON:
2477: continue;
2478: case XOFF:
2479: READCHAR (qdaemon, c, XON_WAIT);
2480: continue;
2481: case CR:
2482: case ZDLE:
2483: return c;
2484: default:
2485: if (fZesc_ctl && !(c & 0140))
2486: continue;
2487: return c;
2488: }
2489: }
2490: }
2491:
2492: /*
2493: * Read a character from the receive buffer, or from the line if empty ...
2494: *
2495: * <timeout> is in seconds (maybe make it tenths of seconds like in Zmodem?)
2496: */
2497:
2498: static int
2499: realreadchar(qdaemon, timeout)
2500: struct sdaemon *qdaemon;
2501: int timeout;
2502: {
2503: int c;
2504:
2505: if ((c = breceive_char (qdaemon->qconn, timeout, TRUE)) >= 0)
2506: return c;
2507:
2508: switch (c) {
2509: case -1:
2510: return ZM_TIMEOUT;
2511: case -2:
2512: return ZM_RCDO;
2513: }
2514:
2515: ulog (LOG_FATAL, "realreadchar: breceive_char() returned %d", c);
2516: return ZM_ERROR;
2517: }
2518:
2519:
2520: /*
2521: * Check if the receive channel has any characters in it.
2522: *
2523: * At present we can only test the receive buffer. No mechanism is available
2524: * to go to the hardware. This should not be a problem though, as long as all
2525: * appropriate calls to fsend_data() set <fdoread> to TRUE.
2526: */
2527:
2528: static boolean
2529: fzreceive_ready()
2530: {
2531: return iPrecstart != iPrecend;
2532: }
2533:
2534: /*
2535: * Store integer value in an achdrval_t ...
2536: */
2537:
2538: static void
2539: stohdr(val, hdr)
2540: hdrval_t val;
2541: achdrval_t hdr;
2542: {
2543: hdr[ZP0] = (char) val;
2544: hdr[ZP1] = (char) (val >> 8);
2545: hdr[ZP2] = (char) (val >> 16);
2546: hdr[ZP3] = (char) (val >> 24);
2547: }
2548:
2549: /*
2550: * Recover an integer from a header ...
2551: */
2552:
2553: static hdrval_t
2554: rclhdr(hdr)
2555: achdrval_t hdr;
2556: {
2557: hdrval_t v;
2558:
2559: v = hdr[ZP3] & 0377;
2560: v = (v << 8) | (hdr[ZP2] & 0377);
2561: v = (v << 8) | (hdr[ZP1] & 0377);
2562: v = (v << 8) | (hdr[ZP0] & 0377);
2563:
2564: return v;
2565: }
2566:
2567: /*
2568: * Encode a <hdrval_t> from the byte count ...
2569: *
2570: * We use to store the byte count / 32 and a message sequence number which
2571: * made this function very useful. Don't remove it.
2572: * FIXME: Well, maybe remove it later.
2573: */
2574:
2575: static hdrval_t
2576: hvzencode_data_hdr(cbytes)
2577: winpos_t cbytes;
2578: {
2579: return (hdrval_t) cbytes;
2580: }
2581:
2582: /*
2583: * Decode a <hdrval_t> into a byte count ...
2584: *
2585: * We use to store the byte count / 32 and a message sequence number which
2586: * made this function very useful. Don't remove it.
2587: * FIXME: Well, maybe remove it later.
2588: */
2589:
2590: static void
2591: zdecode_data_hdr(hdrval, pcbytes)
2592: hdrval_t hdrval;
2593: winpos_t *pcbytes;
2594: {
2595: *pcbytes = hdrval;
2596: }
2597:
2598: /*
2599: * Update <wpZrxpos> from the received data header value ...
2600: *
2601: * FIXME: Here is where we'd handle wrapping around at 4 gigabytes.
2602: */
2603:
2604: static winpos_t
2605: lzupdate_rxpos(rx_hdr, rxpos, lrxpos, txpos)
2606: achdrval_t rx_hdr;
2607: winpos_t rxpos,lrxpos,txpos;
2608: {
2609: winpos_t rx_pktpos;
2610:
2611: zdecode_data_hdr (rclhdr (rx_hdr), &rx_pktpos);
2612:
2613: DEBUG_MESSAGE4 (DEBUG_PROTO,
2614: "lzupdate_rxpos: rx_pktpos=0x%lx, rxpos=0x%lx, lrxpos=0x%lx, txpos=0x%lx",
2615: rx_pktpos, rxpos, lrxpos, txpos);
2616:
2617: /*
2618: * Check if <rx_pktpos> valid. It could be old.
2619: */
2620:
2621: if (rx_pktpos < wpZlrxpos
2622: || rx_pktpos > ((wpZtxpos + 1024L) & ~1023L))
2623: return rxpos;
2624:
2625: return rx_pktpos;
2626: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.