#include "uucp.h"
#if USE_RCS_ID
const char protz_rcsid[] = "$Id: protz.c,v 1.11 2002/02/08 10:35:52 ian Rel $";
#endif
#include <errno.h>
#include "uudefs.h"
#include "uuconf.h"
#include "conn.h"
#include "trans.h"
#include "system.h"
#include "prot.h"
#define ZPROTOCOL_VERSION 1
#define ZPAD '*'
#define ZDLE 030
#define ZBIN 'A'
#define ZHEX 'B'
#define ZINIT 0
#define ZDATA 1
#define ZRPOS 2
#define ZACK 3
#define ZNAK 4
#define Zreserved 5
#define ZINITEND 6
#define ZFIN 7
#define ZCRCE 'h'
#define ZCRCG 'i'
#define ZCRCQ 'j'
#define ZCRCW 'k'
#define ZCRCF 'l'
#define ZRUB0 'm'
#define ZRUB1 'n'
#define GOTOR 0400
#define GOTCRCE (ZCRCE | GOTOR)
#define GOTCRCG (ZCRCG | GOTOR)
#define GOTCRCQ (ZCRCQ | GOTOR)
#define GOTCRCW (ZCRCW | GOTOR)
#define GOTCRCF (ZCRCF | GOTOR)
#define ZF0 3
#define ZF1 2
#define ZF2 1
#define ZF3 0
#define ZP0 0
#define ZP1 1
#define ZP2 2
#define ZP3 3
#define TX_ESCCTL 1
#define ZM_ERROR (-1)
#define ZM_TIMEOUT (-2)
#define ZM_RCDO (-3)
#define LF 012
#define CR 015
#define XON 021
#define XOFF 023
#define XON_WAIT 10
#define CPACKETSIZE 1024
#define CFRAMELEN 12
#define CSUFFIXLEN 10
#define CEXCHANGE_INIT_RETRIES 4
#if ANSI_C
#define IHDRCRC 0xDEBB20E3UL
#else
#define IHDRCRC ((unsigned long) 0xDEBB20E3L)
#endif
#define CPACKBUFSIZE (CFRAMELEN + 2 * CPACKETSIZE + CSUFFIXLEN + 42 )
typedef unsigned char achdrval_t[4];
typedef unsigned long hdrval_t;
typedef unsigned long winpos_t;
#define CTIMEOUT 10
#define CRETRIES 10
#define CSTARTUP_RETRIES 4
#define CGARBAGE 2400
#define CSEND_WINDOW 16384
#define FESCAPE_CONTROL FALSE
static int cZtimeout = CTIMEOUT;
static int cZretries = CRETRIES;
static int cZstartup_retries = CSTARTUP_RETRIES;
static int cZmax_garbage = CGARBAGE;
static int cZtx_window = CSEND_WINDOW;
static int cZrx_buf_len = 0;
static boolean fZesc_ctl = FESCAPE_CONTROL;
struct uuconf_cmdtab asZproto_params[] =
{
{"timeout", UUCONF_CMDTABTYPE_INT, (pointer) & cZtimeout, NULL},
{"retries", UUCONF_CMDTABTYPE_INT, (pointer) & cZretries, NULL},
{"startup-retries", UUCONF_CMDTABTYPE_INT,
(pointer) & cZstartup_retries, NULL},
{"garbage", UUCONF_CMDTABTYPE_INT, (pointer) & cZmax_garbage, NULL},
{"send-window", UUCONF_CMDTABTYPE_INT, (pointer) & cZtx_window, NULL},
{"escape-control", UUCONF_CMDTABTYPE_BOOLEAN, (pointer) & fZesc_ctl,
NULL},
{NULL, 0, NULL, NULL}
};
static unsigned long cZheaders_sent;
static unsigned long cZheaders_received;
static unsigned long cZbytes_resent;
static unsigned long cZtimeouts;
static unsigned long cZerrors;
static char *zZtx_buf;
static char *zZtx_packet_buf;
static char *zZrx_packet_buf;
static unsigned cZblklen;
static unsigned cZtxwspac;
static unsigned cZtxwcnt;
static unsigned cZrxwcnt;
static winpos_t wpZtxstart;
static winpos_t wpZtxpos;
static winpos_t wpZlastsync;
static winpos_t wpZlrxpos;
static winpos_t wpZrxpos;
static int iZlast_tx_data_packet;
static int iZjunk_count;
static int iZtleft;
static int iZbeenhereb4;
static winpos_t wpZrxbytes;
static int iZlast_rx_data_packet;
static char xon = XON;
#ifdef DJE_TESTING
int uucptest = -1;
int uucptest2;
int uucptestseed;
#endif
static int iZpkt_rcvd_kludge;
static hdrval_t hvZpkt_hdrval_kludge;
static const char *azZframe_types[] = {
"Carrier Lost",
"Timeout",
"Error",
#define FTOFFSET 3
"ZINIT",
"ZDATA",
"ZRPOS",
"ZACK",
"ZNAK",
"Zreserved",
"ZINITEND",
"ZFIN",
"UNKNOWN!!!"
};
#define FTNUMBER (sizeof(azZframe_types) / sizeof(char *))
#ifndef min
#define min(a, b) ((a) < (b) ? (a) : (b))
#endif
#define ZZHEADER_NAME(itype) \
azZframe_types[min((size_t) ((itype) + FTOFFSET), FTNUMBER - 1)]
static boolean fzsend_data P((struct sdaemon *qdaemon, char *zdata,
size_t cdata, boolean fendofmessage));
static boolean fzprocess P((struct sdaemon *qdaemon));
static boolean fzstart_proto P((struct sdaemon *qdaemon));
static int izexchange_init P((struct sdaemon *qdaemon, int send_type,
achdrval_t send_val, achdrval_t recv_val));
static boolean fzshutdown_proto P((struct sdaemon *qdaemon));
static boolean fzstart_tx P((void));
static boolean fzfinish_tx P((struct sdaemon *qdaemon, long *plredo));
static boolean fzstart_rx P((void));
static boolean fzfinish_rx P((struct sdaemon *qdaemon));
static boolean fzsend_hdr P((struct sdaemon *qdaemon, int ipkttype,
int ihdrtype, hdrval_t hdrval,
boolean fcheckreceive));
static boolean fzsend_data_packet P((struct sdaemon *qdaemon, char *zdata,
size_t cdata, int frameend,
boolean fcheckreceive));
static int czbuild_header P((char *zresult, int ipkttype, int ihdrtype,
hdrval_t hdrval));
static int czbuild_data_packet P((char *zresult, const char *zdata,
size_t cdata, int frameend));
static int izrecv_hdr P((struct sdaemon *qdaemon, achdrval_t hdr));
static int zrbhdr32 P((struct sdaemon *qdaemon, achdrval_t hdr));
static int zrhhdr P((struct sdaemon *qdaemon, achdrval_t hdr));
static int zrdat32 P((struct sdaemon *qdaemon, char *buf, int length,
int *iprxcount));
static int getinsync P((struct sdaemon *qdaemon, boolean flag));
static char *zputhex P((char *p, int ch));
static char *zputchar P((char *p, int ch));
static int zgethex P((struct sdaemon *qdaemon));
static int zdlread P((struct sdaemon *qdaemon));
static int noxrd7 P((struct sdaemon *qdaemon));
static int realreadchar P((struct sdaemon *qdaemon, int timeout));
static boolean fzreceive_ready P((void));
static void stohdr P((hdrval_t pos, achdrval_t hdr));
static hdrval_t rclhdr P((achdrval_t hdr));
static hdrval_t hvzencode_data_hdr P((winpos_t cbytes));
static void zdecode_data_hdr P((hdrval_t hdrval, winpos_t *pcbytes));
static winpos_t lzupdate_rxpos P((achdrval_t rx_hdr, winpos_t rxpos,
winpos_t lrxpos, winpos_t txpos));
#define READCHAR(qdaemon, b, i) \
(iPrecstart != iPrecend \
? ((b) = BUCHAR (abPrecbuf[iPrecstart]), \
iPrecstart = (iPrecstart + 1) % CRECBUFLEN) \
: ((b) = realreadchar ((qdaemon), (i))))
boolean
fzstart(qdaemon, pzlog)
struct sdaemon *qdaemon;
char **pzlog;
{
*pzlog = zbufalc (sizeof "protocol 'a' starting: , , , , , " + 100);
sprintf (*pzlog, "protocol 'a' starting: %d, %d, %d, %d, %d, %d",
cZtimeout, cZretries, cZstartup_retries,
cZmax_garbage, cZtx_window, fZesc_ctl);
if (! fconn_set (qdaemon->qconn, PARITYSETTING_NONE,
STRIPSETTING_EIGHTBITS, XONXOFF_OFF))
return FALSE;
if (cZtx_window % 1024 != 0 ||
cZtx_window < 4096 || cZtx_window > 65536 ||
65536 % cZtx_window != 0
) {
ulog (LOG_ERROR,
"fzstart: cZtx_window not one of 4096, 8192, 16384, 32768, 65536");
return FALSE;
}
zZtx_buf = (char *) xmalloc (CPACKETSIZE);
zZtx_packet_buf = (char *) xmalloc (CPACKBUFSIZE);
zZrx_packet_buf = (char *) xmalloc (CPACKBUFSIZE);
iZlast_tx_data_packet = -1;
iZlast_rx_data_packet = -1;
wpZtxpos = wpZlrxpos = wpZrxpos = wpZrxbytes = 0;
cZtxwspac = cZtx_window / 4;
cZheaders_sent = cZheaders_received = cZbytes_resent = 0;
cZtimeouts = cZerrors = 0;
iZpkt_rcvd_kludge = -1;
#if 0
if (cZblklen_override > cZtxwspac
|| (!cZblklen_override && cZtxwspac < 1024))
cZblklen_override = cZtxwspac;
#endif
#ifdef DJE_TESTING
{
extern int uucptest,uucptest2,uucptestseed;
FILE *f;
if (uucptest == -1) {
f = fopen ("/usr/local/src/bin/uucp/uucptest", "r");
if (f != NULL) {
fscanf (f, "%d %d %d",
&uucptestseed, &uucptest, &uucptest2);
fclose (f);
}
srand (uucptestseed);
}
}
#endif
if (!fzstart_proto (qdaemon))
return FALSE;
return TRUE;
}
boolean
fzshutdown(qdaemon)
struct sdaemon *qdaemon;
{
(void) fzshutdown_proto (qdaemon);
xfree ((pointer) zZtx_buf);
xfree ((pointer) zZtx_packet_buf);
xfree ((pointer) zZrx_packet_buf);
zZtx_buf = NULL;
zZtx_packet_buf = NULL;
zZrx_packet_buf = NULL;
ulog (LOG_NORMAL,
"Protocol 'a' messages: sent %lu, received %lu",
cZheaders_sent, cZheaders_received);
ulog (LOG_NORMAL,
"Protocol 'a' packets: sent %lu, received %lu",
wpZtxpos / 1024, wpZrxbytes / 1024);
if (cZbytes_resent != 0 || cZtimeouts != 0 || cZerrors != 0)
ulog (LOG_NORMAL,
"Protocol 'a' errors: bytes resent %lu, timeouts %lu, errors %lu",
cZbytes_resent, cZtimeouts, cZerrors);
cZtimeout = CTIMEOUT;
cZretries = CRETRIES;
cZstartup_retries = CSTARTUP_RETRIES;
cZmax_garbage = CGARBAGE;
cZtx_window = CSEND_WINDOW;
fZesc_ctl = FESCAPE_CONTROL;
cZheaders_sent = cZheaders_received = cZbytes_resent = 0;
cZtimeouts = cZerrors = 0;
return TRUE;
}
boolean
fzsendcmd(qdaemon, z, ilocal, iremote)
struct sdaemon *qdaemon;
const char *z;
int ilocal ATTRIBUTE_UNUSED;
int iremote ATTRIBUTE_UNUSED;
{
size_t n,clen;
long lredo;
char *zbuf;
clen = strlen (z) + 1;
DEBUG_MESSAGE1 (DEBUG_PROTO, "fzsendcmd: sending command %s", z);
if (!fzstart_tx ())
return FALSE;
if ((zbuf = zzgetspace (qdaemon, &n)) == NULL)
return FALSE;
#if DEBUG > 0
if (clen > n)
ulog (LOG_FATAL, "fzsendcmd: clen > n");
#endif
strcpy (zbuf, z);
do {
if (!fzsend_data (qdaemon, zbuf, clen, TRUE))
return FALSE;
if (!fzfinish_tx (qdaemon, &lredo))
return FALSE;
} while (lredo >= 0);
return fzprocess (qdaemon);
}
char *
zzgetspace(qdaemon, pclen)
struct sdaemon *qdaemon ATTRIBUTE_UNUSED;
size_t *pclen;
{
*pclen = cZblklen;
return zZtx_buf;
}
boolean
fzsenddata(qdaemon, zdata, cdata, ilocal, iremote, ipos)
struct sdaemon *qdaemon;
char *zdata;
size_t cdata;
int ilocal ATTRIBUTE_UNUSED;
int iremote ATTRIBUTE_UNUSED;
long ipos ATTRIBUTE_UNUSED;
{
DEBUG_MESSAGE1 (DEBUG_PROTO, "fzsenddata: %d bytes", cdata);
if (! fzsend_data (qdaemon, zdata, cdata, cdata == 0))
return FALSE;
return fzprocess (qdaemon);
}
extern struct stransfer *qTsend;
static boolean
fzsend_data(qdaemon, zdata, cdata, fendofmessage)
struct sdaemon *qdaemon;
char *zdata;
size_t cdata;
boolean fendofmessage;
{
size_t n;
if (iZlast_tx_data_packet == -1 || iZlast_tx_data_packet == ZCRCW) {
cZtxwcnt = cZrxwcnt = 0;
iZjunk_count = 0;
if (!fzsend_hdr (qdaemon, ZBIN, ZDATA,
hvzencode_data_hdr (wpZtxpos), TRUE))
return FALSE;
}
n = cdata;
if (fendofmessage)
iZlast_tx_data_packet = ZCRCF;
else if (iZjunk_count > 3)
iZlast_tx_data_packet = ZCRCW;
else if (wpZtxpos == wpZlastsync)
iZlast_tx_data_packet = ZCRCW;
else if (cZrx_buf_len && (cZrxwcnt += n) >= (size_t) cZrx_buf_len)
iZlast_tx_data_packet = ZCRCW;
else if ((cZtxwcnt += n) >= cZtxwspac) {
iZlast_tx_data_packet = ZCRCQ;
cZtxwcnt = 0;
} else
iZlast_tx_data_packet = ZCRCG;
if (++iZtleft > 3) {
iZtleft = 0;
if (cZblklen < 1024)
cZblklen *= 2;
#if 0
if (cZblklen_override && cZblklen > cZblklen_override)
cZblklen = cZblklen_override;
#endif
if (cZblklen > 1024)
cZblklen = 1024;
if (cZrx_buf_len && cZblklen > (size_t) cZrx_buf_len)
cZblklen = cZrx_buf_len;
}
#if DEBUG > 1
if (FDEBUGGING(DEBUG_PROTO)) {
const char *type;
switch (iZlast_tx_data_packet) {
case ZCRCW: type = "ZCRCW"; break;
case ZCRCG: type = "ZCRCG"; break;
case ZCRCQ: type = "ZCRCQ"; break;
case ZCRCE: type = "ZCRCE"; break;
case ZCRCF: type = "ZCRCF"; break;
default : type = "UNKNOWN!!!"; break;
}
DEBUG_MESSAGE3 (DEBUG_PROTO,
"fzsend_data: %s, pos 0x%lx, %d bytes",
type, wpZtxpos, n);
}
#endif
if (!fzsend_data_packet (qdaemon, zdata, n, iZlast_tx_data_packet,
TRUE))
return FALSE;
wpZtxpos += n;
if (iZlast_tx_data_packet == ZCRCW) {
switch (getinsync (qdaemon, FALSE)) {
case ZACK:
break;
case ZRPOS:
if (qTsend == NULL
|| ! ffileisopen (qTsend->e)) {
ulog (LOG_ERROR, "Can't reset non-file");
return FALSE;
}
iZlast_tx_data_packet = -1;
DEBUG_MESSAGE1 (DEBUG_PROTO,
"fzsend_data: Seeking to %ld",
(long) (wpZrxpos - wpZtxstart));
if (!ffileseek (qTsend->e, wpZrxpos - wpZtxstart)) {
ulog (LOG_ERROR, "seek: %s", strerror (errno));
return FALSE;
}
break;
default:
return FALSE;
}
return TRUE;
}
while (wpZtxpos - wpZlrxpos >= (size_t) cZtx_window - 2048) {
if (iZlast_tx_data_packet != ZCRCQ) {
if (!fzsend_data_packet (qdaemon, zdata, (size_t) 0,
iZlast_tx_data_packet = ZCRCQ,
TRUE))
return FALSE;
}
switch (getinsync (qdaemon, TRUE)) {
case ZACK:
break;
case ZRPOS:
if (qTsend == NULL
|| ! ffileisopen (qTsend->e)) {
ulog (LOG_ERROR, "Can't reset non-file");
return FALSE;
}
iZlast_tx_data_packet = -1;
DEBUG_MESSAGE1 (DEBUG_PROTO,
"fzsend_data: Seeking to %ld",
(long) (wpZrxpos - wpZtxstart));
if (!ffileseek (qTsend->e, wpZrxpos - wpZtxstart)) {
ulog (LOG_ERROR, "seek: %s", strerror (errno));
return FALSE;
}
break;
default:
return FALSE;
}
}
return TRUE;
}
static boolean
fzprocess(qdaemon)
struct sdaemon *qdaemon;
{
int c,ch;
while (fzreceive_ready ()) {
READCHAR (qdaemon, ch, 1);
switch (ch) {
case ZPAD:
DEBUG_MESSAGE0 (DEBUG_PROTO,
"fzprocess: possible ZRPOS packet");
iPrecstart = ((iPrecstart + CRECBUFLEN - 1)
% CRECBUFLEN);
c = getinsync (qdaemon, TRUE);
if (c == ZACK)
break;
#if 0
if (!fzsend_data_packet (qdaemon, zZtx_packet_buf,
0, ZCRCE, TRUE))
return FALSE;
#endif
if (c == ZRPOS) {
if (qTsend == NULL
|| ! ffileisopen (qTsend->e)) {
ulog (LOG_ERROR,
"Attempt to back up non-file");
return FALSE;
}
if (! ffileseek (qTsend->e,
wpZrxpos - wpZtxstart)) {
ulog (LOG_ERROR,
"seek: %s", strerror (errno));
return FALSE;
}
iZlast_tx_data_packet = -1;
break;
}
return FALSE;
case XOFF:
case XOFF | 0200:
READCHAR (qdaemon, ch, XON_WAIT);
break;
case CR:
break;
default:
iZjunk_count++;
break;
}
}
return TRUE;
}
boolean
fzwait(qdaemon)
struct sdaemon *qdaemon;
{
int c,cerr,rxcount;
boolean fexit;
achdrval_t rx_hdr;
if (!fzstart_rx ())
return FALSE;
cerr = cZretries;
goto nxthdr;
for (;;) {
if (!fzsend_hdr (qdaemon, ZHEX, ZRPOS,
hvzencode_data_hdr (wpZrxbytes), FALSE))
return FALSE;
nxthdr:
c = izrecv_hdr (qdaemon, rx_hdr);
switch (c) {
case ZM_TIMEOUT:
case ZNAK:
if (--cerr < 0) {
ulog (LOG_ERROR, "fzwait: retries exhausted");
return FALSE;
}
continue;
case ZM_ERROR:
if (--cerr < 0) {
ulog (LOG_ERROR, "fzwait: retries exhausted");
return FALSE;
}
continue;
case ZM_RCDO:
case ZFIN:
return FALSE;
case ZRPOS:
case ZACK:
goto nxthdr;
case ZDATA: {
winpos_t rx_bytes;
zdecode_data_hdr (rclhdr (rx_hdr), &rx_bytes);
DEBUG_MESSAGE2 (DEBUG_PROTO,
"fzwait: bytes(us,them) 0x%lx,0x%lx",
wpZrxbytes, rx_bytes);
if (rx_bytes != wpZrxbytes) {
if (--cerr < 0) {
ulog (LOG_ERROR,
"fzwait: retries exhausted");
return FALSE;
}
(void) zrdat32 (qdaemon, zZrx_packet_buf,
1024, &rxcount);
continue;
}
moredata:
c = zrdat32 (qdaemon, zZrx_packet_buf, 1024,
&rxcount);
#if DEBUG > 1
if (FDEBUGGING(DEBUG_PROTO)) {
const char *msg;
if (c < 0) {
msg = ZZHEADER_NAME(c);
} else {
switch (c) {
case GOTCRCW: msg = "ZCRCW"; break;
case GOTCRCG: msg = "ZCRCG"; break;
case GOTCRCQ: msg = "ZCRCQ"; break;
case GOTCRCE: msg = "ZCRCE"; break;
case GOTCRCF: msg = "ZCRCF"; break;
default : msg = NULL; break;
}
}
if (msg != NULL)
DEBUG_MESSAGE2 (DEBUG_PROTO,
"fzwait: zrdat32: %s, %d bytes",
msg, rxcount);
else
DEBUG_MESSAGE2 (DEBUG_PROTO,
"fzwait: zrdat32: %d, %d bytes",
c, rxcount);
}
#endif
switch (c) {
case ZM_ERROR:
cZerrors++;
if (--cerr < 0) {
ulog (LOG_ERROR,
"fzwait: retries exhausted");
return FALSE;
}
continue;
case ZM_TIMEOUT:
cZtimeouts++;
if (--cerr < 0) {
ulog (LOG_ERROR,
"fzwait: retries exhausted");
return FALSE;
}
continue;
case ZM_RCDO:
return FALSE;
case GOTCRCW:
iZlast_rx_data_packet = ZCRCW;
cerr = cZretries;
if (rxcount != 0
&& !fgot_data (qdaemon, zZrx_packet_buf,
(size_t) rxcount,
(const char *) NULL,
(size_t) 0,
-1, -1, (long) -1,
TRUE, &fexit))
return FALSE;
wpZrxbytes += rxcount;
if (!fzsend_hdr (qdaemon, ZHEX, ZACK,
hvzencode_data_hdr (wpZrxbytes),
FALSE))
return FALSE;
if (! fsend_data (qdaemon->qconn, &xon,
(size_t) 1, FALSE))
return FALSE;
goto nxthdr;
case GOTCRCQ:
iZlast_rx_data_packet = ZCRCQ;
cerr = cZretries;
if (rxcount != 0
&& !fgot_data (qdaemon, zZrx_packet_buf,
(size_t) rxcount,
(const char *) NULL,
(size_t) 0,
-1, -1, (long) -1,
TRUE, &fexit))
return FALSE;
wpZrxbytes += rxcount;
if (!fzsend_hdr (qdaemon, ZHEX, ZACK,
hvzencode_data_hdr (wpZrxbytes),
FALSE))
return FALSE;
goto moredata;
case GOTCRCG:
iZlast_rx_data_packet = ZCRCG;
cerr = cZretries;
if (rxcount != 0
&& !fgot_data (qdaemon, zZrx_packet_buf,
(size_t) rxcount,
(const char *) NULL,
(size_t) 0,
-1, -1, (long) -1,
TRUE, &fexit))
return FALSE;
wpZrxbytes += rxcount;
goto moredata;
case GOTCRCE:
iZlast_rx_data_packet = ZCRCE;
cerr = cZretries;
if (rxcount != 0
&& !fgot_data (qdaemon, zZrx_packet_buf,
(size_t) rxcount,
(const char *) NULL,
(size_t) 0,
-1, -1, (long) -1,
TRUE, &fexit))
return FALSE;
wpZrxbytes += rxcount;
goto nxthdr;
case GOTCRCF:
iZlast_rx_data_packet = ZCRCF;
cerr = cZretries;
wpZrxbytes += rxcount;
if (!fzfinish_rx (qdaemon))
return FALSE;
if (!fgot_data (qdaemon, zZrx_packet_buf,
(size_t) rxcount,
(const char *) NULL,
(size_t) 0, -1, -1,
(long) -1, TRUE, &fexit))
return FALSE;
return TRUE;
}
return FALSE;
}
default:
ulog (LOG_FATAL, "fzwait: received header %s",
ZZHEADER_NAME(c));
return FALSE;
}
}
}
boolean
fzfile(qdaemon, qtrans, fstart, fsend, cbytes, pfhandled)
struct sdaemon *qdaemon;
struct stransfer *qtrans;
boolean fstart;
boolean fsend;
long cbytes ATTRIBUTE_UNUSED;
boolean *pfhandled;
{
long iredo;
*pfhandled = FALSE;
DEBUG_MESSAGE2 (DEBUG_PROTO, "fzfile: fstart=%d, fsend=%d", fstart,
fsend);
if (fsend) {
if (fstart)
return fzstart_tx ();
if (! fzfinish_tx (qdaemon, &iredo))
return FALSE;
if (iredo >= 0) {
if (! ffileisopen (qtrans->e)) {
ulog (LOG_ERROR,
"Attempt to back up non-file");
return FALSE;
}
if (! ffileseek (qtrans->e, iredo)) {
ulog (LOG_ERROR,
"seek: %s", strerror (errno));
return FALSE;
}
*pfhandled = TRUE;
qtrans->fsendfile = TRUE;
return fqueue_send (qdaemon, qtrans);
}
}
return TRUE;
}
#if 0
static unsigned short crctab[256] = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
};
#endif
static unsigned long crc_32_tab[] = {
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL,
0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L,
0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L,
0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L,
0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L,
0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL,
0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L,
0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L,
0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L,
0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L,
0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L,
0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL,
0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL,
0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL,
0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L,
0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L,
0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL,
0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L,
0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL,
0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L,
0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL,
0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L,
0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L,
0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L,
0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L,
0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL,
0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL,
0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L,
0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L,
0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL,
0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L,
0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL,
0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L,
0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL,
0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L,
0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L,
0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL,
0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L,
0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL,
0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL,
0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L,
0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L,
0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL,
0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L,
0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L,
0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L,
0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL,
0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L,
0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L,
0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL,
0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L,
0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL
};
#define updcrc(cp, crc) (crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp)
#define UPDC32(b, crc) \
(crc_32_tab[((unsigned)(crc) ^ (unsigned)(b)) & 0xff] \
^ (((crc) >> 8) & 0x00ffffffL))
static boolean
fzstart_proto(qdaemon)
struct sdaemon *qdaemon;
{
int i;
achdrval_t tx_hdr,rx_hdr;
for (i = 0; i < cZstartup_retries; i++) {
stohdr (0L, tx_hdr);
tx_hdr[ZF0] = ZPROTOCOL_VERSION;
if (fZesc_ctl)
tx_hdr[ZF1] |= TX_ESCCTL;
switch (izexchange_init (qdaemon, ZINIT, tx_hdr, rx_hdr)) {
case -1: return FALSE;
case 0: continue;
case 1: break;
}
#if 0
if (rx_hdr[ZF0] == 0) {
ulog (LOG_ERROR, "Old protocol version, init failed");
return FALSE;
}
#endif
fZesc_ctl = fZesc_ctl || (rx_hdr[ZF1] & TX_ESCCTL) != 0;
stohdr (0L, tx_hdr);
switch (izexchange_init (qdaemon, ZDATA, tx_hdr, rx_hdr)) {
case -1: return FALSE;
case 0: continue;
case 1: break;
}
stohdr (0L, tx_hdr);
switch (izexchange_init (qdaemon, ZACK, tx_hdr, rx_hdr)) {
case -1: return FALSE;
case 0: continue;
case 1: break;
}
stohdr (0L, tx_hdr);
switch (izexchange_init (qdaemon, ZINITEND, tx_hdr, rx_hdr)) {
case -1: return FALSE;
case 0: continue;
case 1: break;
}
DEBUG_MESSAGE0 (DEBUG_PROTO,
"fzstart_proto: Protocol started");
return TRUE;
}
ulog (LOG_ERROR, "Protocol init failed");
return FALSE;
}
static int
izexchange_init(qdaemon, send_type, send_val, recv_val)
struct sdaemon *qdaemon;
int send_type;
achdrval_t send_val;
achdrval_t recv_val;
{
int i,recv_type,count;
for (i = 0; i < CEXCHANGE_INIT_RETRIES; i++) {
if (!fzsend_hdr (qdaemon, send_type == ZDATA ? ZBIN : ZHEX,
send_type, rclhdr (send_val), FALSE))
return -1;
if (send_type == ZDATA) {
count = czbuild_data_packet (zZtx_packet_buf, "",
(size_t) 1, ZCRCF);
if (!fsend_data (qdaemon->qconn, zZtx_packet_buf,
(size_t) count, FALSE))
return -1;
}
recv_type = izrecv_hdr (qdaemon, recv_val);
switch (recv_type) {
case ZM_TIMEOUT:
case ZM_ERROR:
continue;
case ZM_RCDO:
case ZFIN:
return -1;
case ZINIT:
case ZACK:
case ZINITEND:
break;
case ZDATA:
if (zrdat32 (qdaemon, zZrx_packet_buf, 1024, &count)
== GOTCRCF)
break;
continue;
default:
continue;
}
if (recv_type == send_type)
return 1;
if (recv_type > send_type && send_type != ZINIT)
return 0;
if (recv_type == ZINIT && send_type == ZINITEND)
return 0;
}
return 0;
}
static boolean
fzshutdown_proto(qdaemon)
struct sdaemon *qdaemon;
{
(void) fzsend_hdr (qdaemon, ZHEX, ZFIN, 0L, FALSE);
return TRUE;
}
static boolean
fzstart_tx()
{
iZlast_tx_data_packet = -1;
cZblklen = 1024;
wpZlastsync = -1L;
iZbeenhereb4 = 0;
iZtleft = 0;
iZjunk_count = 0;
wpZtxpos = (wpZtxpos + 1024L) & ~1023L;
wpZlrxpos = wpZrxpos = wpZtxpos;
wpZtxstart = wpZtxpos;
return TRUE;
}
static boolean
fzfinish_tx(qdaemon, plredo)
struct sdaemon *qdaemon;
long *plredo;
{
int c,cerr,ctimeouts;
achdrval_t rx_hdr;
winpos_t rx_bytes;
*plredo = -1;
cerr = cZretries;
ctimeouts = 0;
DEBUG_MESSAGE4 (DEBUG_PROTO,
"fzfinish_tx: txpos=0x%lx, rxpos=0x%lx, lrxpos=0x%lx, rxbytes=0x%lx",
wpZtxpos, wpZrxpos, wpZlrxpos, wpZrxbytes);
for (;;) {
c = izrecv_hdr (qdaemon, rx_hdr);
switch (c) {
case ZRPOS:
wpZrxpos = lzupdate_rxpos (rx_hdr, wpZrxpos,
wpZlrxpos, wpZtxpos);
if (((wpZtxpos + 1024) & ~1023) == wpZrxpos)
return TRUE;
cZbytes_resent += wpZtxpos - wpZrxpos;
wpZlrxpos = wpZtxpos = wpZrxpos;
if (wpZlastsync == wpZrxpos) {
if (++iZbeenhereb4 > 4)
if (cZblklen > 32)
cZblklen /= 2;
}
wpZlastsync = wpZrxpos;
iZlast_tx_data_packet = ZCRCW;
*plredo = wpZrxpos - wpZtxstart;
return TRUE;
case ZACK:
wpZrxpos = lzupdate_rxpos (rx_hdr, wpZrxpos,
wpZlrxpos, wpZtxpos);
wpZlrxpos = wpZrxpos;
if (wpZtxpos == wpZrxpos)
return TRUE;
break;
case ZDATA:
zdecode_data_hdr (rclhdr (rx_hdr), &rx_bytes);
if (((wpZrxbytes + 1024L) & ~1023L) == rx_bytes) {
iZpkt_rcvd_kludge = ZDATA;
hvZpkt_hdrval_kludge = rclhdr (rx_hdr);
return TRUE;
}
break;
case ZNAK:
zdecode_data_hdr (rclhdr (rx_hdr), &rx_bytes);
if (((wpZrxbytes + 1024L) & ~1023L) == rx_bytes)
return TRUE;
if (rx_bytes == wpZrxbytes) {
if (!fzsend_hdr (qdaemon, ZHEX, ZACK,
hvzencode_data_hdr (wpZrxbytes),
TRUE))
return FALSE;
}
break;
case ZFIN:
case ZM_RCDO:
return FALSE;
case ZM_TIMEOUT:
if (--cerr < 0) {
ulog (LOG_ERROR,
"fzfinish_tx: retries exhausted");
return FALSE;
}
if (++ctimeouts % 2 == 0)
if (!fzsend_hdr (qdaemon, ZHEX, ZNAK,
hvzencode_data_hdr (wpZtxpos),
TRUE))
return FALSE;
break;
case ZM_ERROR:
default:
if (--cerr < 0) {
ulog (LOG_ERROR,
"fzfinish_tx: retries exhausted");
return FALSE;
}
if (!fzsend_hdr (qdaemon, ZHEX, ZNAK,
hvzencode_data_hdr (wpZtxpos),
TRUE))
return FALSE;
break;
}
}
}
static boolean
fzstart_rx()
{
wpZrxbytes = (wpZrxbytes + 1024L) & ~1023L;
return TRUE;
}
static boolean
fzfinish_rx(qdaemon)
struct sdaemon *qdaemon;
{
DEBUG_MESSAGE0 (DEBUG_PROTO, "fzfinish_rx: message/file received");
return fzsend_hdr (qdaemon, ZHEX, ZACK,
hvzencode_data_hdr (wpZrxbytes), FALSE);
}
static boolean
fzsend_hdr(qdaemon, ipkttype, ihdrtype, hdrval, fcheckreceive)
struct sdaemon *qdaemon;
int ipkttype;
int ihdrtype;
hdrval_t hdrval;
boolean fcheckreceive;
{
int cpacketlen;
DEBUG_MESSAGE2 (DEBUG_PROTO, "fzsend_hdr: %s, data = 0x%lx",
ZZHEADER_NAME(ihdrtype), hdrval);
cpacketlen = czbuild_header (zZtx_packet_buf, ipkttype,
ihdrtype, hdrval);
#ifdef DJE_TESTING
#if 0
if (ihdrtype == ZACK && rand () % 100 < uucptest2) {
cZheaders_sent++;
return TRUE;
}
#else
if (ihdrtype == ZACK || ihdrtype == ZDATA) {
boolean fresult;
int old;
extern int uucptest,uucptest2;
old = uucptest;
uucptest = uucptest2;
cZheaders_sent++;
fresult = fsend_data (qdaemon->qconn, zZtx_packet_buf,
(size_t) cpacketlen, fcheckreceive);
uucptest = old;
return fresult;
}
#endif
#endif
cZheaders_sent++;
return fsend_data (qdaemon->qconn, zZtx_packet_buf,
(size_t) cpacketlen, fcheckreceive);
}
static boolean
fzsend_data_packet(qdaemon, zdata, cdata, frameend, fcheckreceive)
struct sdaemon *qdaemon;
char *zdata;
size_t cdata;
int frameend;
boolean fcheckreceive;
{
int cpacketlen;
cpacketlen = czbuild_data_packet (zZtx_packet_buf, zdata, cdata,
frameend);
return fsend_data (qdaemon->qconn, zZtx_packet_buf,
(size_t) cpacketlen, fcheckreceive);
}
static int
czbuild_header(zresult, ipkttype, ihdrtype, hdrval)
char *zresult;
int ipkttype;
int ihdrtype;
hdrval_t hdrval;
{
char *p;
int i;
unsigned long crc;
achdrval_t achdrval;
p = zresult;
switch (ipkttype) {
case ZBIN:
*p++ = ZPAD;
*p++ = ZDLE;
*p++ = ZBIN;
p = zputchar (p, ihdrtype);
crc = ICRCINIT;
crc = UPDC32 (ihdrtype, crc);
stohdr (hdrval, achdrval);
for (i = 0; i < 4; i++) {
p = zputchar (p, achdrval[i]);
crc = UPDC32 (achdrval[i], crc);
}
crc = ~crc;
for (i = 0; i < 4; i++) {
p = zputchar (p, (char) crc);
crc >>= 8;
}
break;
case ZHEX:
*p++ = ZPAD;
*p++ = ZPAD;
*p++ = ZDLE;
*p++ = ZHEX;
p = zputhex (p, ihdrtype);
crc = ICRCINIT;
crc = UPDC32 (ihdrtype, crc);
stohdr (hdrval, achdrval);
for (i = 0; i < 4; i++) {
p = zputhex (p, achdrval[i]);
crc = UPDC32 (achdrval[i], crc);
}
crc = ~crc;
for (i = 0; i < 4; i++) {
p = zputhex (p, (char) crc);
crc >>= 8;
}
*p++ = CR;
if (ihdrtype != ZFIN && ihdrtype != ZACK)
*p++ = XON;
break;
default:
ulog (LOG_FATAL, "czbuild_header: ipkttype == %d", ipkttype);
break;
}
return p - zresult;
}
static int
czbuild_data_packet(zresult, zdata, cdata, frameend)
char *zresult;
const char *zdata;
size_t cdata;
int frameend;
{
char *p;
unsigned long crc;
p = zresult;
crc = ICRCINIT;
for ( ; cdata-- != 0; zdata++) {
char c;
c = *zdata;
if (c & 0140)
*p++ = c;
else
p = zputchar (p, c);
crc = UPDC32 ((unsigned char) c, crc);
}
*p++ = ZDLE;
*p++ = frameend;
crc = UPDC32 (frameend, crc);
crc = ~crc;
for (cdata = 0; cdata < 4; cdata++) {
p = zputchar (p, (char) crc);
crc >>= 8;
}
if (frameend == ZCRCW || frameend == ZCRCE || frameend == ZCRCF) {
*p++ = CR;
*p++ = XON;
}
return p - zresult;
}
static int
izrecv_hdr(qdaemon, hdr)
struct sdaemon *qdaemon;
achdrval_t hdr;
{
int c,cerr;
if (iZpkt_rcvd_kludge != -1) {
c = iZpkt_rcvd_kludge;
iZpkt_rcvd_kludge = -1;
stohdr (hvZpkt_hdrval_kludge, hdr);
DEBUG_MESSAGE2 (DEBUG_PROTO,
"izrecv_hdr: queued %s, data = 0x%lx",
ZZHEADER_NAME(c), rclhdr (hdr));
cZheaders_received++;
return c;
}
cerr = cZmax_garbage;
again:
switch (c = noxrd7 (qdaemon)) {
case ZM_TIMEOUT:
case ZM_ERROR:
case ZM_RCDO:
goto fifi;
case ZPAD:
break;
case CR:
default:
if (--cerr < 0) {
c = ZM_ERROR;
goto fifi;
}
goto again;
}
splat:
switch (c = noxrd7 (qdaemon)) {
case ZPAD:
if (--cerr < 0) {
c = ZM_ERROR;
goto fifi;
}
goto splat;
case ZM_TIMEOUT:
case ZM_RCDO:
goto fifi;
case ZDLE:
break;
default:
if (--cerr < 0) {
c = ZM_ERROR;
goto fifi;
}
goto again;
}
switch (c = noxrd7 (qdaemon)) {
case ZM_TIMEOUT:
case ZM_RCDO:
goto fifi;
case ZBIN:
c = zrbhdr32 (qdaemon, hdr);
break;
case ZHEX:
c = zrhhdr (qdaemon, hdr);
break;
default:
if (--cerr < 0) {
c = ZM_ERROR;
goto fifi;
}
goto again;
}
fifi:
switch (c) {
case ZM_TIMEOUT:
cZtimeouts++;
break;
case ZM_ERROR:
cZerrors++;
break;
case ZM_RCDO:
break;
default:
cZheaders_received++;
break;
}
DEBUG_MESSAGE2 (DEBUG_PROTO, "izrecv_hdr: %s, data = 0x%lx",
ZZHEADER_NAME(c), rclhdr (hdr));
return c;
}
static int
zrbhdr32(qdaemon, hdr)
struct sdaemon *qdaemon;
achdrval_t hdr;
{
int c,i,type;
unsigned long crc;
if ((c = zdlread (qdaemon)) & ~0377)
return c;
type = c;
crc = ICRCINIT;
crc = UPDC32 (c, crc);
for (i = 0; i < 4; i++) {
if ((c = zdlread (qdaemon)) & ~0377)
return c;
crc = UPDC32 (c, crc);
hdr[i] = (char) c;
}
for (i = 0; i < 4; i++) {
if ((c = zdlread (qdaemon)) & ~0377)
return c;
crc = UPDC32 (c, crc);
}
if (crc != IHDRCRC)
return ZM_ERROR;
return type;
}
static int
zrhhdr(qdaemon, hdr)
struct sdaemon *qdaemon;
achdrval_t hdr;
{
int c,i,type;
unsigned long crc;
if ((c = zgethex (qdaemon)) < 0)
return c;
type = c;
crc = ICRCINIT;
crc = UPDC32 (c, crc);
for (i = 0; i < 4; i++) {
if ((c = zgethex (qdaemon)) < 0)
return c;
crc = UPDC32 (c, crc);
hdr[i] = (char) c;
}
for (i = 0; i < 4; i++) {
if ((c = zgethex (qdaemon)) < 0)
return c;
crc = UPDC32 (c, crc);
}
if (crc != IHDRCRC)
return ZM_ERROR;
return type;
}
static int
zrdat32(qdaemon, buf, length, iprxcount)
struct sdaemon *qdaemon;
char *buf;
int length;
int *iprxcount;
{
int c,d;
unsigned long crc;
char *end;
crc = ICRCINIT;
*iprxcount = 0;
end = buf + length;
while (buf <= end) {
if ((c = zdlread (qdaemon)) & ~0377) {
crcfoo:
switch (c) {
case GOTCRCE:
case GOTCRCG:
case GOTCRCQ:
case GOTCRCW:
case GOTCRCF:
d = c;
c &= 0377;
crc = UPDC32 (c, crc);
if ((c = zdlread (qdaemon)) & ~0377)
goto crcfoo;
crc = UPDC32 (c, crc);
if ((c = zdlread (qdaemon)) & ~0377)
goto crcfoo;
crc = UPDC32 (c, crc);
if ((c = zdlread (qdaemon)) & ~0377)
goto crcfoo;
crc = UPDC32 (c, crc);
if ((c = zdlread (qdaemon)) & ~0377)
goto crcfoo;
crc = UPDC32 (c, crc);
if (crc != IHDRCRC)
return ZM_ERROR;
*iprxcount = length - (end - buf);
return d;
case ZM_TIMEOUT:
case ZM_RCDO:
return c;
default:
return ZM_ERROR;
}
}
*buf++ = (char) c;
crc = UPDC32 (c, crc);
}
return ZM_ERROR;
}
static int
getinsync(qdaemon, flag)
struct sdaemon *qdaemon;
boolean flag;
{
int c,cerr;
achdrval_t rx_hdr;
cerr = cZretries;
for (;;) {
c = izrecv_hdr (qdaemon, rx_hdr);
switch (c) {
case ZRPOS:
wpZrxpos = lzupdate_rxpos (rx_hdr, wpZrxpos,
wpZlrxpos, wpZtxpos);
cZbytes_resent += wpZtxpos - wpZrxpos;
wpZlrxpos = wpZtxpos = wpZrxpos;
if (wpZlastsync == wpZrxpos) {
if (++iZbeenhereb4 > 4)
if (cZblklen > 32)
cZblklen /= 2;
}
wpZlastsync = wpZrxpos;
return ZRPOS;
case ZACK:
wpZrxpos = lzupdate_rxpos (rx_hdr, wpZrxpos,
wpZlrxpos, wpZtxpos);
wpZlrxpos = wpZrxpos;
if (flag || wpZtxpos == wpZrxpos)
return ZACK;
break;
case ZNAK: {
winpos_t rx_bytes;
zdecode_data_hdr (rclhdr (rx_hdr), &rx_bytes);
if (rx_bytes == wpZrxbytes) {
if (!fzsend_hdr (qdaemon, ZHEX, ZACK,
hvzencode_data_hdr (wpZrxbytes),
TRUE))
return FALSE;
}
break;
}
case ZFIN:
case ZM_RCDO:
return c;
case ZM_TIMEOUT:
if (--cerr < 0) {
ulog (LOG_ERROR,
"getinsync: retries exhausted");
return ZM_ERROR;
}
break;
case ZM_ERROR:
default:
if (--cerr < 0) {
ulog (LOG_ERROR,
"getinsync: retries exhausted");
return ZM_ERROR;
}
if (!fzsend_hdr (qdaemon, ZHEX, ZNAK,
hvzencode_data_hdr (wpZtxpos),
TRUE))
return ZM_ERROR;
break;
}
}
}
static char *
zputhex(p, ch)
char *p;
int ch;
{
static char digits[] = "0123456789abcdef";
*p++ = digits[(ch & 0xF0) >> 4];
*p++ = digits[ch & 0xF];
return p;
}
static char *
zputchar(p, ch)
char *p;
int ch;
{
char c = ch;
if (c & 0140) {
*p++ = c;
} else {
switch (c & 0377) {
case ZDLE:
*p++ = ZDLE;
*p++ = c ^ 0100;
break;
case CR:
#if 0
if (!fZesc_ctl && (lastsent & 0177) != '@')
goto sendit;
#endif
case 020:
case XON:
case XOFF:
*p++ = ZDLE;
c ^= 0100;
*p++ = c;
break;
default:
if (fZesc_ctl && !(c & 0140)) {
*p++ = ZDLE;
c ^= 0100;
}
*p++ = c;
break;
}
}
return p;
}
static int
zgethex(qdaemon)
struct sdaemon *qdaemon;
{
int c,n;
if ((c = noxrd7 (qdaemon)) < 0)
return c;
n = c - '0';
if (n > 9)
n -= ('a' - ':');
if (n & ~0xF)
return ZM_ERROR;
if ((c = noxrd7 (qdaemon)) < 0)
return c;
c -= '0';
if (c > 9)
c -= ('a' - ':');
if (c & ~0xF)
return ZM_ERROR;
c += (n << 4);
return c;
}
static int
zdlread(qdaemon)
struct sdaemon *qdaemon;
{
int c;
again:
READCHAR (qdaemon, c, cZtimeout);
if (c < 0)
return c;
if (c & 0140)
return c;
switch (c) {
case ZDLE:
break;
case XON:
goto again;
case XOFF:
READCHAR (qdaemon, c, XON_WAIT);
goto again;
default:
if (fZesc_ctl && !(c & 0140))
goto again;
return c;
}
again2:
READCHAR (qdaemon, c, cZtimeout);
if (c < 0)
return c;
switch (c) {
case ZCRCE:
case ZCRCG:
case ZCRCQ:
case ZCRCW:
case ZCRCF:
return c | GOTOR;
case ZRUB0:
return 0177;
case ZRUB1:
return 0377;
case XON:
goto again2;
case XOFF:
READCHAR (qdaemon, c, XON_WAIT);
goto again2;
default:
if (fZesc_ctl && !(c & 0140))
goto again2;
if ((c & 0140) == 0100)
return c ^ 0100;
break;
}
return ZM_ERROR;
}
static int
noxrd7(qdaemon)
struct sdaemon *qdaemon;
{
int c;
for (;;) {
READCHAR (qdaemon, c, cZtimeout);
if (c < 0)
return c;
switch (c &= 0177) {
case XON:
continue;
case XOFF:
READCHAR (qdaemon, c, XON_WAIT);
continue;
case CR:
case ZDLE:
return c;
default:
if (fZesc_ctl && !(c & 0140))
continue;
return c;
}
}
}
static int
realreadchar(qdaemon, timeout)
struct sdaemon *qdaemon;
int timeout;
{
int c;
if ((c = breceive_char (qdaemon->qconn, timeout, TRUE)) >= 0)
return c;
switch (c) {
case -1:
return ZM_TIMEOUT;
case -2:
return ZM_RCDO;
}
ulog (LOG_FATAL, "realreadchar: breceive_char() returned %d", c);
return ZM_ERROR;
}
static boolean
fzreceive_ready()
{
return iPrecstart != iPrecend;
}
static void
stohdr(val, hdr)
hdrval_t val;
achdrval_t hdr;
{
hdr[ZP0] = (char) val;
hdr[ZP1] = (char) (val >> 8);
hdr[ZP2] = (char) (val >> 16);
hdr[ZP3] = (char) (val >> 24);
}
static hdrval_t
rclhdr(hdr)
achdrval_t hdr;
{
hdrval_t v;
v = hdr[ZP3] & 0377;
v = (v << 8) | (hdr[ZP2] & 0377);
v = (v << 8) | (hdr[ZP1] & 0377);
v = (v << 8) | (hdr[ZP0] & 0377);
return v;
}
static hdrval_t
hvzencode_data_hdr(cbytes)
winpos_t cbytes;
{
return (hdrval_t) cbytes;
}
static void
zdecode_data_hdr(hdrval, pcbytes)
hdrval_t hdrval;
winpos_t *pcbytes;
{
*pcbytes = hdrval;
}
static winpos_t
lzupdate_rxpos(rx_hdr, rxpos, lrxpos, txpos)
achdrval_t rx_hdr;
winpos_t rxpos,lrxpos,txpos;
{
winpos_t rx_pktpos;
zdecode_data_hdr (rclhdr (rx_hdr), &rx_pktpos);
DEBUG_MESSAGE4 (DEBUG_PROTO,
"lzupdate_rxpos: rx_pktpos=0x%lx, rxpos=0x%lx, lrxpos=0x%lx, txpos=0x%lx",
rx_pktpos, rxpos, lrxpos, txpos);
if (rx_pktpos < wpZlrxpos
|| rx_pktpos > ((wpZtxpos + 1024L) & ~1023L))
return rxpos;
return rx_pktpos;
}