Skip to content
Snippets Groups Projects
Commit 483c86de authored by Rob Swindell's avatar Rob Swindell :speech_balloon:
Browse files

ZMODEM Window Management support

The default is still full-streaming mode. The default can be changed by
setting [ZMODEM] MaxWindowSize in sexyz.ini to a maximum window size to
use by default (e.g. "100K"). Additionally, a [ZMODDEM] TargetWindowSize
can be set to a duration (e.g. 60s) to dynamically adjust the maximum
window size to match the through-put rate while keeping the outstanding data
in-flight to an estimated "duration". When TargetWindowSize is used, the
MaxWindowSize only specifies the *initial* maximum window size.

The new '-w' command-line option can be used to control Window Management
support (e.g. over-riding the .ini set default) - by using '-w' or '-w0',
Window Management won't be used or by using '-w<max-size>', a maximum window
size will be imposed (subject to the TargetWindowSize setting mentioned
above). <max-size> can be specified in bytes or multiples (e.g. "-w100K").
Ths option is similar to the [l]sz '-w' option except no space is expected
between '-w' and the (optional) max-size value.

Also new, when receiving [ZMODEM] FullDuplex can be set to FALSE to disable
streaming mode: if the RecvBufSize is not set (0), the sender should use the
subpacket data length (block size, e.g. 1K) as the segment size. Otherwise,
setting FullDuplex=FALSE should produce the same behavior as setting the
RecvBufSize would before (the result being the use of "segmented ZMODEM"
instead of "streaming ZMODEM").

All sexyz command-line options are case-sensitive now (not just the 'cmds').
A lot of code clean-up in zmodem.c.

Incremented zmodem.c rev to 2.0.
Incremented sexyz version to 3.0.
parent c3619942
No related branches found
No related tags found
1 merge request!463MRC mods by Codefenix (2024-10-20)
src/sbbs3/sexyz.c 100644 → 100755
...@@ -87,7 +87,7 @@ ...@@ -87,7 +87,7 @@
/* Global Vars */ /* Global Vars */
/***************/ /***************/
long mode=0; /* Program mode */ long mode=0; /* Program mode */
long zmode=0L; /* Zmodem mode */ long zmode=0L; /* ZMODEM mode */
uchar block[XMODEM_MAX_BLOCK_SIZE]; /* Block buffer */ uchar block[XMODEM_MAX_BLOCK_SIZE]; /* Block buffer */
ulong block_num; /* Block number */ ulong block_num; /* Block number */
char* dszlog; char* dszlog;
...@@ -106,7 +106,7 @@ FILE* errfp; ...@@ -106,7 +106,7 @@ FILE* errfp;
FILE* statfp; FILE* statfp;
FILE* logfp=NULL; FILE* logfp=NULL;
char revision[16]; const char* revision = "3.0";
SOCKET sock=INVALID_SOCKET; SOCKET sock=INVALID_SOCKET;
...@@ -604,7 +604,7 @@ int send_byte(void* unused, uchar ch, unsigned timeout) ...@@ -604,7 +604,7 @@ int send_byte(void* unused, uchar ch, unsigned timeout)
fprintf(statfp,"\b\b\b\b \b\b\b\b"); fprintf(statfp,"\b\b\b\b \b\b\b\b");
if(result!=WAIT_OBJECT_0) { if(result!=WAIT_OBJECT_0) {
lprintf(LOG_WARNING lprintf(LOG_WARNING
,"!TIMEOUT (%d) waiting for output buffer to flush (%u seconds, %u bytes)\n" ,"TIMEOUT (%d) waiting for output buffer to flush (%u seconds, %u bytes)"
,result, timeout, RingBufFull(&outbuf)); ,result, timeout, RingBufFull(&outbuf));
fprintf(statfp fprintf(statfp
,"\n!TIMEOUT (%d) waiting for output buffer to flush (%u seconds, %u bytes)\n" ,"\n!TIMEOUT (%d) waiting for output buffer to flush (%u seconds, %u bytes)\n"
...@@ -972,7 +972,7 @@ static int send_files(char** fname, uint fnames) ...@@ -972,7 +972,7 @@ static int send_files(char** fname, uint fnames)
if(mode&ZMODEM) if(mode&ZMODEM)
success=zmodem_send_file(&zm, path, fp, /* ZRQINIT? */fnum==0, &startfile, &sent_bytes); success=zmodem_send_file(&zm, path, fp, /* ZRQINIT? */fnum==0, &startfile, &sent_bytes);
else /* X/Ymodem */ else /* X/YMODEM */
success=xmodem_send_file(&xm, path, fp, &startfile, &sent_bytes); success=xmodem_send_file(&xm, path, fp, &startfile, &sent_bytes);
fclose(fp); fclose(fp);
...@@ -1138,7 +1138,7 @@ static int receive_files(char** fname_list, int fnames) ...@@ -1138,7 +1138,7 @@ static int receive_files(char** fname_list, int fnames)
lprintf(LOG_DEBUG,"YMODEM header (%u fields): %s", i, block+strlen((char*)block)+1); lprintf(LOG_DEBUG,"YMODEM header (%u fields): %s", i, block+strlen((char*)block)+1);
SAFECOPY(fname,(char*)block); SAFECOPY(fname,(char*)block);
} else { /* Zmodem */ } else { /* ZMODEM */
lprintf(LOG_INFO,"Waiting for ZMODEM sender..."); lprintf(LOG_INFO,"Waiting for ZMODEM sender...");
i=zmodem_recv_init(&zm); i=zmodem_recv_init(&zm);
...@@ -1415,17 +1415,18 @@ static const char* usage= ...@@ -1415,17 +1415,18 @@ static const char* usage=
#endif #endif
"\n" "\n"
"opts = -y allow overwriting of existing files when receiving\n" "opts = -y allow overwriting of existing files when receiving\n"
" -o disable Zmodem CRC-32 mode (use CRC-16)\n" " -k enable X/YMODEM-1K send mode\n"
" -s disable Zmodem streaming (Slow Zmodem)\n" " -c enable XMODEM-CRC receive mode\n"
" -k enable X/Ymodem-1K send mode\n" " -g enable X/YMODEM-G receive mode (no error recovery)\n"
" -c enable Xmodem-CRC receive mode\n" " -o disable ZMODEM CRC-32 mode (use CRC-16)\n"
" -g enable X/Ymodem-G receive mode (no error recovery)\n" " -s use segmented ZMODEM (disable streaming)\n"
" -2 set maximum Zmodem block size to 2K\n" " -2 set maximum ZMODEM block size to 2K\n"
" -4 set maximum Zmodem block size to 4K\n" " -4 set maximum ZMODEM block size to 4K\n"
" -8 set maximum Zmodem block size to 8K (ZedZap)\n" " -8 set maximum ZMODEM block size to 8K (ZedZap)\n"
" -m# set maximum receive file size to # bytes (0=unlimited, default=%u)\n" " -w# set maximum ZMODEM transmit window size (default=0, unlimited)\n"
" -! to pause after abnormal exit (error)\n" " -m# set maximum receive file size to # bytes (default=0, unlimited)\n"
" -l lowercase received filenames\n" " -l lowercase received filenames\n"
" -! to pause after abnormal exit (error)\n"
#ifdef __unix__ #ifdef __unix__
" -telnet to enable Telnet mode (the default except in stdio mode)\n" " -telnet to enable Telnet mode (the default except in stdio mode)\n"
#else #else
...@@ -1434,11 +1435,11 @@ static const char* usage= ...@@ -1434,11 +1435,11 @@ static const char* usage=
" -rlogin or -ssh or -raw to disable Telnet mode\n" " -rlogin or -ssh or -raw to disable Telnet mode\n"
"\n" "\n"
"cmd = v to display detailed version information\n" "cmd = v to display detailed version information\n"
" sx to send Xmodem rx to receive Xmodem\n" " sx to send XMODEM rx to receive XMODEM\n"
" sX to send Xmodem-1K rc to receive Xmodem-CRC\n" " sX to send XMODEM-1K rc to receive XMODEM-CRC\n"
" sy to send Ymodem ry to receive Ymodem\n" " sy to send YMODEM ry to receive YMODEM\n"
" sY to send Ymodem-1K rg to receive Ymodem-G\n" " sY to send YMODEM-1K rg to receive YMODEM-G\n"
" sz to send Zmodem rz to receive Zmodem\n" " sz to send ZMODEM rz to receive ZMODEM\n"
"\n" "\n"
"file = filename to send or receive\n" "file = filename to send or receive\n"
"path = directory to receive files into\n" "path = directory to receive files into\n"
...@@ -1508,7 +1509,6 @@ int main(int argc, char **argv) ...@@ -1508,7 +1509,6 @@ int main(int argc, char **argv)
int retval; int retval;
uint fnames=0; uint fnames=0;
FILE* fp; FILE* fp;
BOOL tcp_nodelay;
char compiler[32]; char compiler[32];
BOOL telnet_requested=FALSE; BOOL telnet_requested=FALSE;
str_list_t ini = strListInit(); str_list_t ini = strListInit();
...@@ -1525,13 +1525,10 @@ int main(int argc, char **argv) ...@@ -1525,13 +1525,10 @@ int main(int argc, char **argv)
statfp=stdout; statfp=stdout;
#endif #endif
sscanf("$Revision: 2.10 $", "%*s %s", revision);
fprintf(statfp,"\nSynchronet External X/Y/ZMODEM v%s-%s" fprintf(statfp,"\nSynchronet External X/Y/ZMODEM v%s-%s"
" Copyright %s Rob Swindell\n\n" " Copyright Rob Swindell\n\n"
,revision ,revision
,PLATFORM_DESC ,PLATFORM_DESC
,&__DATE__[7]
); );
xmodem_init(&xm,NULL,&mode,lputs,xmodem_progress,send_byte,recv_byte,is_connected,NULL,flush); xmodem_init(&xm,NULL,&mode,lputs,xmodem_progress,send_byte,recv_byte,is_connected,NULL,flush);
...@@ -1555,8 +1552,6 @@ int main(int argc, char **argv) ...@@ -1555,8 +1552,6 @@ int main(int argc, char **argv)
fclose(fp); fclose(fp);
} }
tcp_nodelay =iniGetBool(ini, ROOT_SECTION,"TCP_NODELAY",TRUE);
telnet =iniGetBool(ini, ROOT_SECTION,"Telnet",TRUE); telnet =iniGetBool(ini, ROOT_SECTION,"Telnet",TRUE);
debug_tx =iniGetBool(ini, ROOT_SECTION,"DebugTx",FALSE); debug_tx =iniGetBool(ini, ROOT_SECTION,"DebugTx",FALSE);
debug_rx =iniGetBool(ini, ROOT_SECTION,"DebugRx",FALSE); debug_rx =iniGetBool(ini, ROOT_SECTION,"DebugRx",FALSE);
...@@ -1578,36 +1573,42 @@ int main(int argc, char **argv) ...@@ -1578,36 +1573,42 @@ int main(int argc, char **argv)
if(iniGetBool(ini, ROOT_SECTION,"Debug",FALSE)) if(iniGetBool(ini, ROOT_SECTION,"Debug",FALSE))
log_level=LOG_DEBUG; log_level=LOG_DEBUG;
xm.send_timeout =iniGetInteger(ini, "Xmodem","SendTimeout",xm.send_timeout); /* seconds */ const char* section = "XMODEM";
xm.recv_timeout =iniGetInteger(ini, "Xmodem","RecvTimeout",xm.recv_timeout); /* seconds */ xm.send_timeout =iniGetInteger(ini, section,"SendTimeout",xm.send_timeout); /* seconds */
xm.byte_timeout =iniGetInteger(ini, "Xmodem","ByteTimeout",xm.byte_timeout); /* seconds */ xm.recv_timeout =iniGetInteger(ini, section,"RecvTimeout",xm.recv_timeout); /* seconds */
xm.ack_timeout =iniGetInteger(ini, "Xmodem","AckTimeout",xm.ack_timeout); /* seconds */ xm.byte_timeout =iniGetInteger(ini, section,"ByteTimeout",xm.byte_timeout); /* seconds */
xm.block_size =(ulong)iniGetBytes(ini, "Xmodem","BlockSize",1,xm.block_size); /* 128 or 1024 */ xm.ack_timeout =iniGetInteger(ini, section,"AckTimeout",xm.ack_timeout); /* seconds */
xm.max_block_size =(ulong)iniGetBytes(ini, "Xmodem","MaxBlockSize",1,xm.max_block_size); /* 128 or 1024 */ xm.block_size =(ulong)iniGetBytes(ini, section,"BlockSize",1,xm.block_size); /* 128 or 1024 */
xm.max_errors =iniGetInteger(ini, "Xmodem","MaxErrors",xm.max_errors); xm.max_block_size =(ulong)iniGetBytes(ini, section,"MaxBlockSize",1,xm.max_block_size); /* 128 or 1024 */
xm.g_delay =iniGetInteger(ini, "Xmodem","G_Delay",xm.g_delay); xm.max_errors =iniGetInteger(ini, section,"MaxErrors",xm.max_errors);
xm.crc_mode_supported =iniGetBool(ini, "Xmodem","SendCRC",xm.crc_mode_supported); xm.g_delay =iniGetInteger(ini, section,"G_Delay",xm.g_delay);
xm.g_mode_supported =iniGetBool(ini, "Xmodem","SendG",xm.g_mode_supported); xm.crc_mode_supported =iniGetBool(ini, section,"SendCRC",xm.crc_mode_supported);
xm.g_mode_supported =iniGetBool(ini, section,"SendG",xm.g_mode_supported);
xm.fallback_to_xmodem =iniGetInteger(ini, "Ymodem","FallbackToXmodem", xm.fallback_to_xmodem);
xm.fallback_to_xmodem =iniGetInteger(ini, "YMODEM","FallbackToXmodem", xm.fallback_to_xmodem);
zm.init_timeout =iniGetInteger(ini, "Zmodem","InitTimeout",zm.init_timeout); /* seconds */
zm.send_timeout =iniGetInteger(ini, "Zmodem","SendTimeout",zm.send_timeout); /* seconds */ section = "ZMODEM";
zm.recv_timeout =iniGetInteger(ini, "Zmodem","RecvTimeout",zm.recv_timeout); /* seconds */ zm.init_timeout =iniGetInteger(ini, section,"InitTimeout",zm.init_timeout); /* seconds */
zm.crc_timeout =iniGetInteger(ini, "Zmodem","CrcTimeout",zm.crc_timeout); /* seconds */ zm.send_timeout =iniGetInteger(ini, section,"SendTimeout",zm.send_timeout); /* seconds */
zm.block_size =(ulong)iniGetBytes(ini, "Zmodem","BlockSize",1,zm.block_size); /* 1024 */ zm.recv_timeout =iniGetInteger(ini, section,"RecvTimeout",zm.recv_timeout); /* seconds */
zm.max_block_size =(ulong)iniGetBytes(ini, "Zmodem","MaxBlockSize",1,zm.max_block_size); /* 1024 or 8192 */ zm.crc_timeout =iniGetInteger(ini, section,"CrcTimeout",zm.crc_timeout); /* seconds */
zm.max_errors =iniGetInteger(ini, "Zmodem","MaxErrors",zm.max_errors); zm.block_size =(ulong)iniGetBytes(ini, section,"BlockSize",1,zm.block_size); /* 1024 */
zm.recv_bufsize =(ulong)iniGetBytes(ini, "Zmodem","RecvBufSize",1,0); zm.max_block_size =(ulong)iniGetBytes(ini, section,"MaxBlockSize",1,zm.max_block_size); /* 1024 or 8192 */
zm.no_streaming =!iniGetBool(ini, "Zmodem","Streaming",TRUE); zm.max_errors =iniGetInteger(ini, section,"MaxErrors",zm.max_errors);
zm.want_fcs_16 =!iniGetBool(ini, "Zmodem","CRC32",TRUE); zm.recv_bufsize =(ulong)iniGetBytes(ini, section,"RecvBufSize",1,0);
zm.escape_telnet_iac =iniGetBool(ini, "Zmodem","EscapeTelnetIAC",TRUE); zm.no_streaming =!iniGetBool(ini, section,"Streaming",TRUE);
zm.escape_8th_bit =iniGetBool(ini, "Zmodem","Escape8thBit",FALSE); zm.want_fcs_16 =!iniGetBool(ini, section,"CRC32",TRUE);
zm.escape_ctrl_chars =iniGetBool(ini, "Zmodem","EscapeCtrlChars",FALSE); zm.can_full_duplex =iniGetBool(ini, section,"FullDuplex",TRUE);
zm.escape_telnet_iac =iniGetBool(ini, section,"EscapeTelnetIAC",TRUE);
dszlog_path =iniGetBool(ini, "DSZLOG","Path",TRUE); zm.escape_8th_bit =iniGetBool(ini, section,"Escape8thBit",FALSE);
dszlog_short =iniGetBool(ini, "DSZLOG","Short",FALSE); zm.escape_ctrl_chars =iniGetBool(ini, section,"EscapeCtrlChars",FALSE);
dszlog_quotes =iniGetBool(ini, "DSZLOG","Quotes",FALSE); zm.max_window_size =(uint32_t)iniGetBytes(ini, section,"MaxWindowSize",1,0);
zm.target_window_size =iniGetDuration(ini, section,"TargetWindowSize",0);
section = "DSZLOG";
dszlog_path =iniGetBool(ini, section, "Path",TRUE);
dszlog_short =iniGetBool(ini, section, "Short",FALSE);
dszlog_quotes =iniGetBool(ini, section, "Quotes",FALSE);
if(zm.recv_bufsize > 0xffff) if(zm.recv_bufsize > 0xffff)
zm.recv_bufsize = 0xffff; zm.recv_bufsize = 0xffff;
...@@ -1669,7 +1670,7 @@ int main(int argc, char **argv) ...@@ -1669,7 +1670,7 @@ int main(int argc, char **argv)
case 'Y': case 'Y':
mode|=(YMODEM|CRC); mode|=(YMODEM|CRC);
break; break;
case 'k': /* Ymodem-Checksum for debug/test purposes only */ case 'k': /* YMODEM-Checksum for debug/test purposes only */
mode|=YMODEM; mode|=YMODEM;
break; break;
case 'g': case 'g':
...@@ -1682,7 +1683,7 @@ int main(int argc, char **argv) ...@@ -1682,7 +1683,7 @@ int main(int argc, char **argv)
break; break;
default: default:
fprintf(statfp,"Unrecognized command '%s'\n\n",argv[i]); fprintf(statfp,"Unrecognized command '%s'\n\n",argv[i]);
fprintf(statfp,usage,MAX_FILE_SIZE); fprintf(statfp,usage);
bail(1); bail(1);
return -1; return -1;
} }
...@@ -1729,11 +1730,11 @@ int main(int argc, char **argv) ...@@ -1729,11 +1730,11 @@ int main(int argc, char **argv)
dszlog_quotes=TRUE; dszlog_quotes=TRUE;
continue; continue;
} }
switch(toupper(*arg)) { switch(*arg) {
case 'K': /* sz/rz compatible */ case 'k': /* sz/rz compatible */
xm.block_size=XMODEM_MAX_BLOCK_SIZE; xm.block_size=XMODEM_MAX_BLOCK_SIZE;
break; break;
case 'C': /* sz/rz compatible */ case 'c': /* sz/rz compatible */
mode|=CRC; mode|=CRC;
break; break;
case '2': case '2':
...@@ -1745,25 +1746,28 @@ int main(int argc, char **argv) ...@@ -1745,25 +1746,28 @@ int main(int argc, char **argv)
case '8': /* ZedZap */ case '8': /* ZedZap */
zm.max_block_size=8192; zm.max_block_size=8192;
break; break;
case 'O': /* disable Zmodem CRC-32 */ case 'o': /* disable ZMODEM CRC-32 */
zm.want_fcs_16=TRUE; zm.want_fcs_16=TRUE;
break; break;
case 'S': /* disable Zmodem streaming */ case 's': /* disable ZMODEM streaming */
zm.no_streaming=TRUE; zm.no_streaming=TRUE;
break; break;
case 'G': /* Ymodem-G or Xmodem-G (a.k.a. Qmodem-G) */ case 'w': /* Max ZMODEM Transmit Window Size */
zm.max_window_size = parse_byte_count(arg + 1, /* units: */1);
break;
case 'g': /* YMODEM-G or XMODEM-G (a.k.a. Qmodem-G) */
mode|=(GMODE|CRC); mode|=(GMODE|CRC);
break; break;
case 'Y': case 'y':
mode|=OVERWRITE; mode|=OVERWRITE;
break; break;
case '!': case '!':
pause_on_abend=TRUE; pause_on_abend=TRUE;
break; break;
case 'M': /* MaxFileSize */ case 'm': /* MaxFileSize */
max_file_size=strtoul(arg + 1,NULL,0); /* TODO: use strtoull() ? */ max_file_size = parse_byte_count(arg + 1, /* units: */1);
break; break;
case 'L': /* Lowercase received filenames */ case 'l': /* Lowercase received filenames */
lc_filenames=TRUE; lc_filenames=TRUE;
break; break;
} }
...@@ -1819,14 +1823,14 @@ int main(int argc, char **argv) ...@@ -1819,14 +1823,14 @@ int main(int argc, char **argv)
if(!(mode&(SEND|RECV))) { if(!(mode&(SEND|RECV))) {
fprintf(statfp,"!No command specified\n\n"); fprintf(statfp,"!No command specified\n\n");
fprintf(statfp,usage,MAX_FILE_SIZE); fprintf(statfp,usage);
bail(1); bail(1);
return -1; return -1;
} }
if(mode&(SEND|XMODEM) && !fnames) { /* Sending with any or recv w/Xmodem */ if(mode&(SEND|XMODEM) && !fnames) { /* Sending with any or recv w/XMODEM */
fprintf(statfp,"!Must specify filename or filelist\n\n"); fprintf(statfp,"!Must specify filename or filelist\n\n");
fprintf(statfp,usage,MAX_FILE_SIZE); fprintf(statfp,usage);
bail(1); bail(1);
return -1; return -1;
} }
...@@ -1845,7 +1849,7 @@ int main(int argc, char **argv) ...@@ -1845,7 +1849,7 @@ int main(int argc, char **argv)
init_stdio(); init_stdio();
#else #else
fprintf(statfp,"!No socket descriptor specified\n\n"); fprintf(statfp,"!No socket descriptor specified\n\n");
fprintf(errfp,usage,MAX_FILE_SIZE); fprintf(errfp,usage);
bail(1); bail(1);
return -1; return -1;
#endif #endif
...@@ -1875,6 +1879,19 @@ int main(int argc, char **argv) ...@@ -1875,6 +1879,19 @@ int main(int argc, char **argv)
lprintf(LOG_DEBUG, "Setting socket options"); lprintf(LOG_DEBUG, "Setting socket options");
if(iniGetSocketOptions(ini, "sockopts", sock, error, sizeof(error)) != 0) if(iniGetSocketOptions(ini, "sockopts", sock, error, sizeof(error)) != 0)
lprintf(LOG_ERR, "ERROR %s", error); lprintf(LOG_ERR, "ERROR %s", error);
int value = 0;
socklen_t len = sizeof(value);
if(getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)&value, &len) == 0)
lprintf(LOG_DEBUG, "Socket send buffer length: %d bytes", value);
value = 0;
len = sizeof(value);
if(getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&value, &len) == 0)
lprintf(LOG_DEBUG, "Socket receive buffer length: %d bytes", value);
value = 0;
len = sizeof(value);
if(getsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&value, &len) == 0)
lprintf(LOG_DEBUG, "Socket TCP_NODELAY: %d", value);
#ifdef __unix__ #ifdef __unix__
} }
#endif #endif
......
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
/* Synchronet ZMODEM Functions */ /* Synchronet ZMODEM Functions */
/* $Id: zmodem.c,v 1.124 2019/08/25 03:05:34 rswindell Exp $ */
/******************************************************************************/ /******************************************************************************/
/* Project : Unite! File : zmodem general Version : 1.02 */ /* Project : Unite! File : zmodem general Version : 1.02 */
/* */ /* */
...@@ -62,6 +60,8 @@ ...@@ -62,6 +60,8 @@
#define BADSUBPKT 0x80 #define BADSUBPKT 0x80
#define SEND_SUCCESS 0
#define HDRLEN 5 /* size of a zmodem header */ #define HDRLEN 5 /* size of a zmodem header */
static int lprintf(zmodem_t* zm, int level, const char *fmt, ...) static int lprintf(zmodem_t* zm, int level, const char *fmt, ...)
...@@ -96,7 +96,7 @@ static BOOL is_cancelled(zmodem_t* zm) ...@@ -96,7 +96,7 @@ static BOOL is_cancelled(zmodem_t* zm)
return(zm->cancelled); return(zm->cancelled);
} }
int zmodem_data_waiting(zmodem_t* zm, unsigned timeout) static BOOL is_data_waiting(zmodem_t* zm, unsigned timeout)
{ {
if(zm->data_waiting) if(zm->data_waiting)
return(zm->data_waiting(zm->cbdata, timeout)); return(zm->data_waiting(zm->cbdata, timeout));
...@@ -111,7 +111,7 @@ static char *chr(int ch) ...@@ -111,7 +111,7 @@ static char *chr(int ch)
case TIMEOUT: return("TIMEOUT"); case TIMEOUT: return("TIMEOUT");
case ABORTED: return("ABORTED"); case ABORTED: return("ABORTED");
case SUBPKTOVERFLOW: return "Subpacket Overflow"; case SUBPKTOVERFLOW: return "Subpacket Overflow";
case CRCFAILED: return "CRC Failure"; case CRCFAILED: return "CRC ERROR";
case INVALIDSUBPKT: return "Invalid Subpacket"; case INVALIDSUBPKT: return "Invalid Subpacket";
case ZRQINIT: return("ZRQINIT"); case ZRQINIT: return("ZRQINIT");
case ZRINIT: return("ZRINIT"); case ZRINIT: return("ZRINIT");
...@@ -241,7 +241,7 @@ int zmodem_send_raw(zmodem_t* zm, unsigned char ch) ...@@ -241,7 +241,7 @@ int zmodem_send_raw(zmodem_t* zm, unsigned char ch)
{ {
int result; int result;
if((result = zm->send_byte(zm->cbdata, ch, zm->send_timeout)) != 0) if((result = zm->send_byte(zm->cbdata, ch, zm->send_timeout)) != SEND_SUCCESS)
lprintf(zm, LOG_ERR, "%s ERROR: %d", __FUNCTION__, result); lprintf(zm, LOG_ERR, "%s ERROR: %d", __FUNCTION__, result);
else else
zm->last_sent = ch; zm->last_sent = ch;
...@@ -257,7 +257,7 @@ int zmodem_send_esc(zmodem_t* zm, unsigned char c) ...@@ -257,7 +257,7 @@ int zmodem_send_esc(zmodem_t* zm, unsigned char c)
{ {
int result; int result;
if((result = zmodem_send_raw(zm, ZDLE)) != 0) { if((result = zmodem_send_raw(zm, ZDLE)) != SEND_SUCCESS) {
lprintf(zm, LOG_ERR, "%s ERROR: %d", __FUNCTION__, result); lprintf(zm, LOG_ERR, "%s ERROR: %d", __FUNCTION__, result);
return result; return result;
} }
...@@ -291,7 +291,7 @@ int zmodem_tx(zmodem_t* zm, unsigned char c) ...@@ -291,7 +291,7 @@ int zmodem_tx(zmodem_t* zm, unsigned char c)
break; break;
case TELNET_IAC: case TELNET_IAC:
if(zm->escape_telnet_iac) { if(zm->escape_telnet_iac) {
if((result=zmodem_send_raw(zm, ZDLE))!=0) if((result=zmodem_send_raw(zm, ZDLE)) != SEND_SUCCESS)
return(result); return(result);
return zmodem_send_raw(zm, ZRUB1); return zmodem_send_raw(zm, ZRUB1);
} }
...@@ -317,7 +317,7 @@ int zmodem_send_hex(zmodem_t* zm, uchar val) ...@@ -317,7 +317,7 @@ int zmodem_send_hex(zmodem_t* zm, uchar val)
// lprintf(zm, LOG_DEBUG, __FUNCTION__ " %02X",val); // lprintf(zm, LOG_DEBUG, __FUNCTION__ " %02X",val);
if((result=zmodem_send_raw(zm, xdigit[val>>4]))!=0) if((result=zmodem_send_raw(zm, xdigit[val>>4])) != SEND_SUCCESS)
return result; return result;
return zmodem_send_raw(zm, xdigit[val&0xf]); return zmodem_send_raw(zm, xdigit[val&0xf]);
} }
...@@ -326,9 +326,9 @@ int zmodem_send_padded_zdle(zmodem_t* zm) ...@@ -326,9 +326,9 @@ int zmodem_send_padded_zdle(zmodem_t* zm)
{ {
int result; int result;
if((result=zmodem_send_raw(zm, ZPAD))!=0) if((result=zmodem_send_raw(zm, ZPAD)) != SEND_SUCCESS)
return result; return result;
if((result=zmodem_send_raw(zm, ZPAD))!=0) if((result=zmodem_send_raw(zm, ZPAD)) != SEND_SUCCESS)
return result; return result;
return zmodem_send_raw(zm, ZDLE); return zmodem_send_raw(zm, ZDLE);
} }
...@@ -347,10 +347,10 @@ int zmodem_send_hex_header(zmodem_t* zm, unsigned char * p) ...@@ -347,10 +347,10 @@ int zmodem_send_hex_header(zmodem_t* zm, unsigned char * p)
// lprintf(zm, LOG_DEBUG, __FUNCTION__ " %s", chr(type)); // lprintf(zm, LOG_DEBUG, __FUNCTION__ " %s", chr(type));
if((result=zmodem_send_padded_zdle(zm))!=0) if((result=zmodem_send_padded_zdle(zm)) != SEND_SUCCESS)
return result; return result;
if((result=zmodem_send_raw(zm, ZHEX))!=0) if((result=zmodem_send_raw(zm, ZHEX)) != SEND_SUCCESS)
return result; return result;
/* /*
...@@ -364,7 +364,7 @@ int zmodem_send_hex_header(zmodem_t* zm, unsigned char * p) ...@@ -364,7 +364,7 @@ int zmodem_send_hex_header(zmodem_t* zm, unsigned char * p)
*/ */
for(i=0;i<HDRLEN;i++) { for(i=0;i<HDRLEN;i++) {
if((result=zmodem_send_hex(zm, *p))!=0) if((result=zmodem_send_hex(zm, *p)) != SEND_SUCCESS)
return result; return result;
crc = ucrc16(*p, crc); crc = ucrc16(*p, crc);
p++; p++;
...@@ -378,18 +378,18 @@ int zmodem_send_hex_header(zmodem_t* zm, unsigned char * p) ...@@ -378,18 +378,18 @@ int zmodem_send_hex_header(zmodem_t* zm, unsigned char * p)
* transmit the crc * transmit the crc
*/ */
if((result=zmodem_send_hex(zm, (uchar)(crc>>8)))!=0) if((result=zmodem_send_hex(zm, (uchar)(crc>>8))) != SEND_SUCCESS)
return result; return result;
if((result=zmodem_send_hex(zm, (uchar)(crc&0xff)))!=0) if((result=zmodem_send_hex(zm, (uchar)(crc&0xff))) != SEND_SUCCESS)
return result; return result;
/* /*
* end of line sequence * end of line sequence
*/ */
if((result=zmodem_send_raw(zm, '\r'))!=0) if((result=zmodem_send_raw(zm, '\r')) != SEND_SUCCESS)
return result; return result;
if((result=zmodem_send_raw(zm, '\n'))!=0) /* FDSZ sends 0x8a instead of 0x0a */ if((result=zmodem_send_raw(zm, '\n')) != SEND_SUCCESS) /* FDSZ sends 0x8a instead of 0x0a */
return result; return result;
if(type!=ZACK && type!=ZFIN) if(type!=ZACK && type!=ZFIN)
...@@ -412,27 +412,27 @@ int zmodem_send_bin32_header(zmodem_t* zm, unsigned char * p) ...@@ -412,27 +412,27 @@ int zmodem_send_bin32_header(zmodem_t* zm, unsigned char * p)
// lprintf(zm, LOG_DEBUG, __FUNCTION__ " %s", chr(*p)); // lprintf(zm, LOG_DEBUG, __FUNCTION__ " %s", chr(*p));
if((result=zmodem_send_padded_zdle(zm))!=0) if((result=zmodem_send_padded_zdle(zm)) != SEND_SUCCESS)
return result; return result;
if((result=zmodem_send_raw(zm, ZBIN32))!=0) if((result=zmodem_send_raw(zm, ZBIN32)) != SEND_SUCCESS)
return result; return result;
crc = 0xffffffffL; crc = 0xffffffffL;
for(i=0;i<HDRLEN;i++) { for(i=0;i<HDRLEN;i++) {
crc = ucrc32(*p,crc); crc = ucrc32(*p,crc);
if((result=zmodem_tx(zm, *p++))!=0) if((result=zmodem_tx(zm, *p++)) != SEND_SUCCESS)
return result; return result;
} }
crc = ~crc; crc = ~crc;
if((result= zmodem_tx(zm, (uchar)((crc ) & 0xff)))!=0) if((result= zmodem_tx(zm, (uchar)((crc ) & 0xff))) != SEND_SUCCESS)
return result; return result;
if((result= zmodem_tx(zm, (uchar)((crc >> 8) & 0xff)))!=0) if((result= zmodem_tx(zm, (uchar)((crc >> 8) & 0xff))) != SEND_SUCCESS)
return result; return result;
if((result= zmodem_tx(zm, (uchar)((crc >> 16) & 0xff)))!=0) if((result= zmodem_tx(zm, (uchar)((crc >> 16) & 0xff))) != SEND_SUCCESS)
return result; return result;
return zmodem_tx(zm, (uchar)((crc >> 24) & 0xff)); return zmodem_tx(zm, (uchar)((crc >> 24) & 0xff));
} }
...@@ -445,21 +445,21 @@ int zmodem_send_bin16_header(zmodem_t* zm, unsigned char * p) ...@@ -445,21 +445,21 @@ int zmodem_send_bin16_header(zmodem_t* zm, unsigned char * p)
// lprintf(zm, LOG_DEBUG, __FUNCTION__ " %s", chr(*p)); // lprintf(zm, LOG_DEBUG, __FUNCTION__ " %s", chr(*p));
if((result=zmodem_send_padded_zdle(zm))!=0) if((result=zmodem_send_padded_zdle(zm)) != SEND_SUCCESS)
return result; return result;
if((result=zmodem_send_raw(zm, ZBIN))!=0) if((result=zmodem_send_raw(zm, ZBIN)) != SEND_SUCCESS)
return result; return result;
crc = 0; crc = 0;
for(i=0;i<HDRLEN;i++) { for(i=0;i<HDRLEN;i++) {
crc = ucrc16(*p,crc); crc = ucrc16(*p,crc);
if((result=zmodem_tx(zm, *p++))!=0) if((result=zmodem_tx(zm, *p++)) != SEND_SUCCESS)
return result; return result;
} }
if((result= zmodem_tx(zm, (uchar)(crc >> 8)))!=0) if((result= zmodem_tx(zm, (uchar)(crc >> 8))) != SEND_SUCCESS)
return result; return result;
return zmodem_tx(zm, (uchar)(crc&0xff)); return zmodem_tx(zm, (uchar)(crc&0xff));
} }
...@@ -494,25 +494,25 @@ int zmodem_send_data32(zmodem_t* zm, uchar subpkt_type, unsigned char * p, size_ ...@@ -494,25 +494,25 @@ int zmodem_send_data32(zmodem_t* zm, uchar subpkt_type, unsigned char * p, size_
while(l > 0) { while(l > 0) {
crc = ucrc32(*p,crc); crc = ucrc32(*p,crc);
if((result=zmodem_tx(zm, *p++))!=0) if((result=zmodem_tx(zm, *p++)) != SEND_SUCCESS)
return result; return result;
l--; l--;
} }
crc = ucrc32(subpkt_type, crc); crc = ucrc32(subpkt_type, crc);
if((result=zmodem_send_raw(zm, ZDLE))!=0) if((result=zmodem_send_raw(zm, ZDLE)) != SEND_SUCCESS)
return result; return result;
if((result=zmodem_send_raw(zm, subpkt_type))!=0) if((result=zmodem_send_raw(zm, subpkt_type)) != SEND_SUCCESS)
return result; return result;
crc = ~crc; crc = ~crc;
if((result= zmodem_tx(zm, (uchar) ((crc ) & 0xff)))!=0) if((result= zmodem_tx(zm, (uchar) ((crc ) & 0xff))) != SEND_SUCCESS)
return result; return result;
if((result= zmodem_tx(zm, (uchar) ((crc >> 8 ) & 0xff)))!=0) if((result= zmodem_tx(zm, (uchar) ((crc >> 8 ) & 0xff))) != SEND_SUCCESS)
return result; return result;
if((result= zmodem_tx(zm, (uchar) ((crc >> 16) & 0xff)))!=0) if((result= zmodem_tx(zm, (uchar) ((crc >> 16) & 0xff))) != SEND_SUCCESS)
return result; return result;
return zmodem_tx(zm, (uchar) ((crc >> 24) & 0xff)); return zmodem_tx(zm, (uchar) ((crc >> 24) & 0xff));
} }
...@@ -528,42 +528,47 @@ int zmodem_send_data16(zmodem_t* zm, uchar subpkt_type,unsigned char * p, size_t ...@@ -528,42 +528,47 @@ int zmodem_send_data16(zmodem_t* zm, uchar subpkt_type,unsigned char * p, size_t
while(l > 0) { while(l > 0) {
crc = ucrc16(*p,crc); crc = ucrc16(*p,crc);
if((result=zmodem_tx(zm, *p++))!=0) if((result=zmodem_tx(zm, *p++)) != SEND_SUCCESS)
return result; return result;
l--; l--;
} }
crc = ucrc16(subpkt_type,crc); crc = ucrc16(subpkt_type,crc);
if((result=zmodem_send_raw(zm, ZDLE))!=0) if((result=zmodem_send_raw(zm, ZDLE)) != SEND_SUCCESS)
return result; return result;
if((result=zmodem_send_raw(zm, subpkt_type))!=0) if((result=zmodem_send_raw(zm, subpkt_type)) != SEND_SUCCESS)
return result; return result;
if((result= zmodem_tx(zm, (uchar)(crc >> 8)))!=0) if((result= zmodem_tx(zm, (uchar)(crc >> 8))) != SEND_SUCCESS)
return result; return result;
return zmodem_tx(zm, (uchar)(crc&0xff)); return zmodem_tx(zm, (uchar)(crc&0xff));
} }
BOOL zmodem_end_of_frame(int subpkt_type)
{
return subpkt_type == ZCRCW || subpkt_type == ZCRCE;
}
/* /*
* send a data subpacket using crc 16 or crc 32 as desired by the receiver * send a data subpacket using crc 16 or crc 32 as desired by the receiver
*/ */
int zmodem_send_data_subpkt(zmodem_t* zm, uchar subpkt_type, unsigned char * p, size_t l) int zmodem_send_data_subpkt(zmodem_t* zm, uchar subpkt_type, unsigned char* data, size_t len)
{ {
int result; int result;
if(subpkt_type == ZCRCW || subpkt_type == ZCRCE) /* subpacket indicating 'end-of-frame' */ if(zmodem_end_of_frame(subpkt_type))
zm->frame_in_transit=FALSE; zm->frame_in_transit=FALSE;
else /* other subpacket (mid-frame) */ else /* other subpacket (mid-frame) */
zm->frame_in_transit=TRUE; zm->frame_in_transit=TRUE;
if(!zm->want_fcs_16 && zm->can_fcs_32) { if(!zm->want_fcs_16 && zm->can_fcs_32) {
if((result=zmodem_send_data32(zm, subpkt_type,p,l))!=0) if((result=zmodem_send_data32(zm, subpkt_type, data, len)) != SEND_SUCCESS)
return result; return result;
} }
else { else {
if((result=zmodem_send_data16(zm, subpkt_type,p,l))!=0) if((result=zmodem_send_data16(zm, subpkt_type, data, len)) != SEND_SUCCESS)
return result; return result;
} }
...@@ -575,7 +580,7 @@ int zmodem_send_data_subpkt(zmodem_t* zm, uchar subpkt_type, unsigned char * p, ...@@ -575,7 +580,7 @@ int zmodem_send_data_subpkt(zmodem_t* zm, uchar subpkt_type, unsigned char * p,
return result; return result;
} }
int zmodem_send_data(zmodem_t* zm, uchar subpkt_type, unsigned char * p, size_t len) int zmodem_send_data(zmodem_t* zm, uchar subpkt_type, unsigned char* data, size_t len)
{ {
if(!zm->frame_in_transit) { /* Start of frame, include ZDATA header */ if(!zm->frame_in_transit) { /* Start of frame, include ZDATA header */
lprintf(zm, LOG_DEBUG, "%lu %s Start of frame: %s" lprintf(zm, LOG_DEBUG, "%lu %s Start of frame: %s"
...@@ -583,7 +588,7 @@ int zmodem_send_data(zmodem_t* zm, uchar subpkt_type, unsigned char * p, size_t ...@@ -583,7 +588,7 @@ int zmodem_send_data(zmodem_t* zm, uchar subpkt_type, unsigned char * p, size_t
zmodem_send_pos_header(zm, ZDATA, (uint32_t)zm->current_file_pos, /* Hex? */ FALSE); zmodem_send_pos_header(zm, ZDATA, (uint32_t)zm->current_file_pos, /* Hex? */ FALSE);
} }
return zmodem_send_data_subpkt(zm, subpkt_type, p, len); return zmodem_send_data_subpkt(zm, subpkt_type, data, len);
} }
int zmodem_send_pos_header(zmodem_t* zm, int type, int32_t pos, BOOL hex) int zmodem_send_pos_header(zmodem_t* zm, int type, int32_t pos, BOOL hex)
...@@ -862,7 +867,7 @@ int zmodem_recv_data32(zmodem_t* zm, unsigned char * p, unsigned maxlen, unsigne ...@@ -862,7 +867,7 @@ int zmodem_recv_data32(zmodem_t* zm, unsigned char * p, unsigned maxlen, unsigne
rxd_crc |= zmodem_rx(zm) << 24; rxd_crc |= zmodem_rx(zm) << 24;
if(rxd_crc != crc) { if(rxd_crc != crc) {
lprintf(zm,LOG_WARNING, "%lu %s CRC ERROR (%08lX, expected: %08lX) Bytes=%u, subpacket type=%s" lprintf(zm, LOG_DEBUG, "%lu %s CRC ERROR (%08lX, expected: %08lX) Bytes=%u, subpacket type=%s"
,(ulong)zm->ack_file_pos, __FUNCTION__, rxd_crc, crc, *len, chr(subpkt_type)); ,(ulong)zm->ack_file_pos, __FUNCTION__, rxd_crc, crc, *len, chr(subpkt_type));
return CRCFAILED; return CRCFAILED;
} }
...@@ -911,7 +916,7 @@ int zmodem_recv_data16(zmodem_t* zm, register unsigned char* p, unsigned maxlen, ...@@ -911,7 +916,7 @@ int zmodem_recv_data16(zmodem_t* zm, register unsigned char* p, unsigned maxlen,
rxd_crc |= zmodem_rx(zm); rxd_crc |= zmodem_rx(zm);
if(rxd_crc != crc) { if(rxd_crc != crc) {
lprintf(zm,LOG_WARNING, "%lu %s CRC ERROR (%04hX, expected: %04hX) Bytes=%u, subpacket type=%s" lprintf(zm, LOG_DEBUG, "%lu %s CRC ERROR (%04hX, expected: %04hX) Bytes=%u, subpacket type=%s"
,(ulong)zm->ack_file_pos, __FUNCTION__, rxd_crc, crc, *len, chr(subpkt_type)); ,(ulong)zm->ack_file_pos, __FUNCTION__, rxd_crc, crc, *len, chr(subpkt_type));
return CRCFAILED; return CRCFAILED;
} }
...@@ -923,7 +928,7 @@ int zmodem_recv_data16(zmodem_t* zm, register unsigned char* p, unsigned maxlen, ...@@ -923,7 +928,7 @@ int zmodem_recv_data16(zmodem_t* zm, register unsigned char* p, unsigned maxlen,
return subpkt_type; return subpkt_type;
} }
int zmodem_recv_data(zmodem_t* zm, unsigned char* p, size_t maxlen, unsigned* len, BOOL ack, int* type) int zmodem_recv_data(zmodem_t* zm, unsigned char* buf, size_t maxlen, unsigned* len, BOOL ack, int* type)
{ {
int subpkt_type; int subpkt_type;
unsigned n=0; unsigned n=0;
...@@ -940,15 +945,15 @@ int zmodem_recv_data(zmodem_t* zm, unsigned char* p, size_t maxlen, unsigned* le ...@@ -940,15 +945,15 @@ int zmodem_recv_data(zmodem_t* zm, unsigned char* p, size_t maxlen, unsigned* le
*len = 0; *len = 0;
if(zm->receive_32bit_data) { if(zm->receive_32bit_data) {
subpkt_type = zmodem_recv_data32(zm, p, maxlen, len, type); subpkt_type = zmodem_recv_data32(zm, buf, maxlen, len, type);
} }
else { else {
subpkt_type = zmodem_recv_data16(zm, p, maxlen, len, type); subpkt_type = zmodem_recv_data16(zm, buf, maxlen, len, type);
} }
if(subpkt_type <= 0) { /* e.g. TIMEOUT, SUBPKTOVERFLOW, CRCFAILED */ if(subpkt_type <= 0) { /* e.g. TIMEOUT, SUBPKTOVERFLOW, CRCFAILED */
lprintf(zm, LOG_WARNING, "%lu %s ERROR: %s (after %u bytes)" lprintf(zm, LOG_WARNING, "%s data subpacket (%u bytes) %s"
,(ulong)zm->ack_file_pos, __FUNCTION__, chr(subpkt_type), *len); ,chr(*type), *len, chr(subpkt_type));
return(subpkt_type); return(subpkt_type);
} }
...@@ -995,7 +1000,7 @@ BOOL zmodem_recv_subpacket(zmodem_t* zm, BOOL ack, int* type) ...@@ -995,7 +1000,7 @@ BOOL zmodem_recv_subpacket(zmodem_t* zm, BOOL ack, int* type)
result = zmodem_recv_data(zm,zm->rx_data_subpacket, sizeof(zm->rx_data_subpacket), &len, ack, type); result = zmodem_recv_data(zm,zm->rx_data_subpacket, sizeof(zm->rx_data_subpacket), &len, ack, type);
if(result != FRAMEOK && result != ENDOFFRAME) { if(result != FRAMEOK && result != ENDOFFRAME) {
lprintf(zm, LOG_ERR, "%lu %s ERROR: %s (subpacket type: %s, %u bytes)" lprintf(zm, LOG_DEBUG, "%lu %s ERROR: %s (subpacket type: %s, %u bytes)"
,(ulong)zm->ack_file_pos, __FUNCTION__, chr(result), chr(*type), len); ,(ulong)zm->ack_file_pos, __FUNCTION__, chr(result), chr(*type), len);
zmodem_send_znak(zm); zmodem_send_znak(zm);
return(FALSE); return(FALSE);
...@@ -1100,7 +1105,7 @@ BOOL zmodem_recv_bin16_header(zmodem_t* zm) ...@@ -1100,7 +1105,7 @@ BOOL zmodem_recv_bin16_header(zmodem_t* zm)
// lprintf(zm,LOG_DEBUG, "%lu %s GOOD CRC: %04hX", __FUNCTION__ // lprintf(zm,LOG_DEBUG, "%lu %s GOOD CRC: %04hX", __FUNCTION__
// ,(ulong)zm->ack_file_pos, __FUNCTION__, crc); // ,(ulong)zm->ack_file_pos, __FUNCTION__, crc);
zm->rxd_header_len = 5; zm->rxd_header_len = n;
return(TRUE); return(TRUE);
} }
...@@ -1143,7 +1148,7 @@ BOOL zmodem_recv_hex_header(zmodem_t* zm) ...@@ -1143,7 +1148,7 @@ BOOL zmodem_recv_hex_header(zmodem_t* zm)
if(rxd_crc == crc) { if(rxd_crc == crc) {
// lprintf(zm,LOG_DEBUG, "%s GOOD CRC: %04hX", __FUNCTION__, crc); // lprintf(zm,LOG_DEBUG, "%s GOOD CRC: %04hX", __FUNCTION__, crc);
zm->rxd_header_len = 5; zm->rxd_header_len = i;
} }
else { else {
lprintf(zm,LOG_WARNING, "%s CRC ERROR: 0x%hX, expected: 0x%hX" lprintf(zm,LOG_WARNING, "%s CRC ERROR: 0x%hX, expected: 0x%hX"
...@@ -1203,7 +1208,7 @@ BOOL zmodem_recv_bin32_header(zmodem_t* zm) ...@@ -1203,7 +1208,7 @@ BOOL zmodem_recv_bin32_header(zmodem_t* zm)
} }
// lprintf(zm,LOG_DEBUG, "%lu %s GOOD CRC: %08lX", (ulong)zm->ack_file_pos, __FUNCTION__, crc); // lprintf(zm,LOG_DEBUG, "%lu %s GOOD CRC: %08lX", (ulong)zm->ack_file_pos, __FUNCTION__, crc);
zm->rxd_header_len = 5; zm->rxd_header_len = n;
return(TRUE); return(TRUE);
} }
...@@ -1369,7 +1374,7 @@ BOOL zmodem_recv_crc(zmodem_t* zm, uint32_t* crc) ...@@ -1369,7 +1374,7 @@ BOOL zmodem_recv_crc(zmodem_t* zm, uint32_t* crc)
{ {
int type; int type;
if(!zmodem_data_waiting(zm,zm->crc_timeout)) { if(!is_data_waiting(zm,zm->crc_timeout)) {
lprintf(zm,LOG_ERR, "%lu %s Timeout waiting for response (%u seconds)" lprintf(zm,LOG_ERR, "%lu %s Timeout waiting for response (%u seconds)"
,(ulong)zm->current_file_pos, __FUNCTION__, zm->crc_timeout); ,(ulong)zm->current_file_pos, __FUNCTION__, zm->crc_timeout);
return(FALSE); return(FALSE);
...@@ -1425,7 +1430,7 @@ int zmodem_get_zrinit(zmodem_t* zm) ...@@ -1425,7 +1430,7 @@ int zmodem_get_zrinit(zmodem_t* zm)
zmodem_send_raw(zm,'\r'); zmodem_send_raw(zm,'\r');
zmodem_send_hex_header(zm,zrqinit_header); zmodem_send_hex_header(zm,zrqinit_header);
if(!zmodem_data_waiting(zm,zm->init_timeout)) if(!is_data_waiting(zm,zm->init_timeout))
return(TIMEOUT); return(TIMEOUT);
return zmodem_recv_header(zm); return zmodem_recv_header(zm);
} }
...@@ -1434,6 +1439,7 @@ int zmodem_send_zrinit(zmodem_t* zm) ...@@ -1434,6 +1439,7 @@ int zmodem_send_zrinit(zmodem_t* zm)
{ {
unsigned char zrinit_header[] = { ZRINIT, 0, 0, 0, 0 }; unsigned char zrinit_header[] = { ZRINIT, 0, 0, 0, 0 };
if(zm->can_full_duplex)
zrinit_header[ZF0] = ZF0_CANFDX; zrinit_header[ZF0] = ZF0_CANFDX;
if(!zm->no_streaming) if(!zm->no_streaming)
...@@ -1452,7 +1458,7 @@ int zmodem_send_zrinit(zmodem_t* zm) ...@@ -1452,7 +1458,7 @@ int zmodem_send_zrinit(zmodem_t* zm)
zrinit_header[ZF0] |= ZF0_ESC8; zrinit_header[ZF0] |= ZF0_ESC8;
if(zm->no_streaming && zm->recv_bufsize==0) if(zm->no_streaming && zm->recv_bufsize==0)
zm->recv_bufsize = sizeof(zm->rx_data_subpacket); zm->recv_bufsize = zm->max_block_size;
zrinit_header[ZP0] = zm->recv_bufsize & 0xff; zrinit_header[ZP0] = zm->recv_bufsize & 0xff;
zrinit_header[ZP1] = zm->recv_bufsize >> 8; zrinit_header[ZP1] = zm->recv_bufsize >> 8;
...@@ -1474,7 +1480,7 @@ int zmodem_get_zfin(zmodem_t* zm) ...@@ -1474,7 +1480,7 @@ int zmodem_get_zfin(zmodem_t* zm)
result = zmodem_send_zabort(zm); result = zmodem_send_zabort(zm);
else else
result = zmodem_send_zfin(zm); result = zmodem_send_zfin(zm);
if(result != 0) if(result != SEND_SUCCESS)
return result; return result;
if((type = zmodem_recv_header(zm)) == ZFIN) if((type = zmodem_recv_header(zm)) == ZFIN)
break; break;
...@@ -1496,9 +1502,10 @@ int zmodem_get_zfin(zmodem_t* zm) ...@@ -1496,9 +1502,10 @@ int zmodem_get_zfin(zmodem_t* zm)
BOOL zmodem_handle_zrpos(zmodem_t* zm, uint64_t* pos) BOOL zmodem_handle_zrpos(zmodem_t* zm, uint64_t* pos)
{ {
if(zm->rxd_header_pos <= zm->current_file_size) { if(zm->rxd_header_pos < zm->current_file_size) {
if(*pos != zm->rxd_header_pos) { if(*pos != zm->rxd_header_pos) {
*pos = zm->rxd_header_pos; *pos = zm->rxd_header_pos;
zm->ack_file_pos = *pos;
lprintf(zm, LOG_INFO, "%lu Resuming transfer from offset: %"PRIu64 lprintf(zm, LOG_INFO, "%lu Resuming transfer from offset: %"PRIu64
,(ulong)zm->current_file_pos, *pos); ,(ulong)zm->current_file_pos, *pos);
} }
...@@ -1510,10 +1517,11 @@ BOOL zmodem_handle_zrpos(zmodem_t* zm, uint64_t* pos) ...@@ -1510,10 +1517,11 @@ BOOL zmodem_handle_zrpos(zmodem_t* zm, uint64_t* pos)
return FALSE; return FALSE;
} }
BOOL zmodem_handle_zack(zmodem_t* zm) BOOL zmodem_handle_zack(zmodem_t* zm, uint32_t min, uint32_t max)
{ {
if(zm->rxd_header_pos == zm->current_file_pos) { if(zm->rxd_header_pos >= min && zm->rxd_header_pos <= max) {
lprintf(zm, LOG_DEBUG, "%lu Received valid ZACK", zm->rxd_header_pos); lprintf(zm, LOG_DEBUG, "%lu Received valid ZACK", zm->rxd_header_pos);
zm->ack_file_pos = zm->rxd_header_pos;
return TRUE; return TRUE;
} }
lprintf(zm, LOG_WARNING, "%lu Received INVALID ZACK, offset: %lu" lprintf(zm, LOG_WARNING, "%lu Received INVALID ZACK, offset: %lu"
...@@ -1521,6 +1529,17 @@ BOOL zmodem_handle_zack(zmodem_t* zm) ...@@ -1521,6 +1529,17 @@ BOOL zmodem_handle_zack(zmodem_t* zm)
return FALSE; return FALSE;
} }
static unsigned new_window_size(zmodem_t* zm, time_t start, unsigned pos)
{
time_t elapsed = time(NULL) - start;
if(elapsed < 1)
elapsed = 1;
unsigned cps = pos / elapsed;
if(cps < 1)
cps = 1;
return cps * zm->target_window_size;
}
/* /*
* send from the current position in the file * send from the current position in the file
* all the way to end of file or until something goes wrong. * all the way to end of file or until something goes wrong.
...@@ -1530,11 +1549,14 @@ BOOL zmodem_handle_zack(zmodem_t* zm) ...@@ -1530,11 +1549,14 @@ BOOL zmodem_handle_zack(zmodem_t* zm)
int zmodem_send_from(zmodem_t* zm, FILE* fp, uint64_t pos, uint64_t* sent) int zmodem_send_from(zmodem_t* zm, FILE* fp, uint64_t pos, uint64_t* sent)
{ {
size_t n; size_t len;
uchar type; uchar tx_type;
unsigned buf_sent = 0; unsigned buf_sent = 0;
unsigned subpkts_sent = 0; unsigned subpkts_sent = 0;
unsigned backchannel_wait = 0;
time_t start = time(NULL);
lprintf(zm, LOG_DEBUG, "%lu %s", (ulong)pos, __FUNCTION__);
if(sent!=NULL) if(sent!=NULL)
*sent=0; *sent=0;
...@@ -1546,23 +1568,67 @@ int zmodem_send_from(zmodem_t* zm, FILE* fp, uint64_t pos, uint64_t* sent) ...@@ -1546,23 +1568,67 @@ int zmodem_send_from(zmodem_t* zm, FILE* fp, uint64_t pos, uint64_t* sent)
} }
zm->current_file_pos = pos; zm->current_file_pos = pos;
/* /*
* send the data in the file * send the data in the file
*/ */
while(is_connected(zm)) { while(is_connected(zm)) {
/*
* characters from the other side
* check out that header
*/
if(zm->consecutive_errors && backchannel_wait == 0)
backchannel_wait = 1;
while(is_data_waiting(zm, backchannel_wait) && !is_cancelled(zm) && is_connected(zm)) {
int rx_type;
int c;
lprintf(zm, LOG_DEBUG, "Back-channel traffic detected");
if((c = zmodem_recv_raw(zm)) < 0) {
lprintf(zm, LOG_ERR, "Back-channel receive ERROR: %s", chr(c));
return(c);
}
if(c == ZPAD) {
rx_type = zmodem_recv_header(zm);
lprintf(zm,LOG_DEBUG, "Received back-channel data: %s", chr(rx_type));
if(rx_type == ZACK && zmodem_handle_zack(zm, zm->ack_file_pos, zm->current_file_pos)) {
zm->current_window_size = zm->current_file_pos - zm->ack_file_pos;
lprintf(zm, LOG_DEBUG, "%lu Asynchronous acknowledgment (ZACK) of %lu bytes, new window: %lu"
,(ulong)zm->current_file_pos, (ulong)zm->ack_file_pos, (ulong)zm->current_window_size);
if(zm->max_window_size && zm->target_window_size) {
zm->max_window_size = new_window_size(zm, start, zm->rxd_header_pos);
lprintf(zm, LOG_DEBUG, "%lu New window size: %lu (%u seconds of data)"
,(ulong)zm->current_file_pos, (ulong)zm->max_window_size, zm->target_window_size);
}
continue;
}
else if(rx_type >= 0) {
zmodem_send_data(zm, ZCRCE, /* data: */NULL, /* len: */0);
return rx_type;
}
} else
lprintf(zm,LOG_INFO, "Unexpected back-channel data received: %s", chr(c));
}
if(is_cancelled(zm))
return(ZCAN);
/* /*
* read a block from the file * read a block from the file
*/ */
pos = zm->current_file_pos; pos = zm->current_file_pos;
n = fread(zm->tx_data_subpacket,sizeof(BYTE),zm->block_size,fp); if(zm->max_window_size && zm->current_window_size >= zm->max_window_size) {
lprintf(zm, LOG_WARNING, "%lu Transmit-Window management: %lu >= %lu"
,(ulong)zm->current_file_pos, (ulong)zm->current_window_size, (ulong)zm->max_window_size);
backchannel_wait = 1;
continue;
}
len = fread(zm->tx_data_subpacket,sizeof(BYTE),zm->block_size,fp);
if(zm->progress!=NULL) if(zm->progress!=NULL)
zm->progress(zm->cbdata, ftello(fp)); zm->progress(zm->cbdata, ftello(fp));
type = ZCRCW; tx_type = ZCRCW;
/** ZMODEM.DOC: /** ZMODEM.DOC:
ZCRCW data subpackets expect a response before the next frame is sent. ZCRCW data subpackets expect a response before the next frame is sent.
...@@ -1571,36 +1637,43 @@ int zmodem_send_from(zmodem_t* zm, FILE* fp, uint64_t pos, uint64_t* sent) ...@@ -1571,36 +1637,43 @@ int zmodem_send_from(zmodem_t* zm, FILE* fp, uint64_t pos, uint64_t* sent)
the receiver to write its buffer before sending more data. the receiver to write its buffer before sending more data.
***/ ***/
/* Note: we always use ZCRCW for the first frame */ /* Note: we always use ZCRCW for the first frame */
if(subpkts_sent || n < zm->block_size) { if(subpkts_sent || len < zm->block_size) {
/* ZMODEM.DOC: /* ZMODEM.DOC:
In the absence of fatal error, the sender eventually encounters end of In the absence of fatal error, the sender eventually encounters end of
file. If the end of file is encountered within a frame, the frame is file. If the end of file is encountered within a frame, the frame is
closed with a ZCRCE data subpacket which does not elicit a response closed with a ZCRCE data subpacket which does not elicit a response
except in case of error. except in case of error.
*/ */
if(n < zm->block_size) if(len < zm->block_size || zm->consecutive_errors)
type = ZCRCE; tx_type = ZCRCE;
else { else {
if(zm->can_overlap_io && !zm->no_streaming && (zm->recv_bufsize==0 || buf_sent+n < zm->recv_bufsize)) if(zm->can_overlap_io && !zm->no_streaming && (zm->recv_bufsize==0 || buf_sent + len < zm->recv_bufsize)) {
type = ZCRCG; if(zm->can_full_duplex && zm->max_window_size)
tx_type = (subpkts_sent % (zm->max_window_size / zm->block_size / 4)) == 0 ? ZCRCQ : ZCRCG;
else
tx_type = ZCRCG;
}
else /* Send a ZCRCW frame */ else /* Send a ZCRCW frame */
buf_sent = 0; buf_sent = 0;
} }
} }
/* Note: No support for sending ZCRCQ data subpackets here */ lprintf(zm, LOG_DEBUG, "%lu Sending %s data subpacket (%u bytes) window: %lu / %lu"
,(ulong)pos, chr(tx_type), len, (ulong)zm->current_window_size, (ulong)zm->max_window_size);
if(zmodem_send_data(zm, type, zm->tx_data_subpacket, n) != 0) if(zmodem_send_data(zm, tx_type, zm->tx_data_subpacket, len) != SEND_SUCCESS) {
return(TIMEOUT); zm->consecutive_errors++;
continue;
}
zm->current_file_pos += n; zm->current_window_size += len;
zm->current_file_pos += len;
if(zm->current_file_pos > zm->current_file_size) if(zm->current_file_pos > zm->current_file_size)
zm->current_file_size = zm->current_file_pos; zm->current_file_size = zm->current_file_pos;
subpkts_sent++; subpkts_sent++;
if(type == ZCRCW || type == ZCRCE) { if(zmodem_end_of_frame(tx_type)) {
lprintf(zm, LOG_DEBUG, "%lu Sent end-of-frame (%s subpacket)",(ulong)pos, chr(type)); lprintf(zm, LOG_DEBUG, "%lu Sent end-of-frame (%s subpacket)", (ulong)pos, chr(tx_type));
if(type == ZCRCW) { /* ZACK expected */ if(tx_type == ZCRCW) { /* ZACK expected */
lprintf(zm, LOG_DEBUG, "%lu Waiting for ZACK", (ulong)pos); lprintf(zm, LOG_DEBUG, "%lu Waiting for ZACK", (ulong)pos);
while(is_connected(zm)) { while(is_connected(zm)) {
int ack; int ack;
...@@ -1610,54 +1683,25 @@ int zmodem_send_from(zmodem_t* zm, FILE* fp, uint64_t pos, uint64_t* sent) ...@@ -1610,54 +1683,25 @@ int zmodem_send_from(zmodem_t* zm, FILE* fp, uint64_t pos, uint64_t* sent)
if(is_cancelled(zm)) if(is_cancelled(zm))
return(ZCAN); return(ZCAN);
if(zmodem_handle_zack(zm)) if(zmodem_handle_zack(zm, zm->current_file_pos, zm->current_file_pos)) {
zm->current_window_size = 0;
break; break;
} }
} }
} }
}
if(sent!=NULL) if(sent!=NULL)
*sent+=n; *sent += len;
buf_sent+=n; buf_sent += len;
if(n < zm->block_size) { if(len < zm->block_size) {
lprintf(zm, LOG_DEBUG, "%lu End of file (or read error) reached", (ulong)zm->current_file_pos); lprintf(zm, LOG_DEBUG, "%lu End of file (or read error) reached", (ulong)zm->current_file_pos);
zmodem_send_zeof(zm); zmodem_send_zeof(zm);
return zmodem_recv_header(zm); /* If this is ZRINIT, Success */ return zmodem_recv_header(zm); /* If this is ZRINIT, Success */
} }
backchannel_wait = 0;
/*
* characters from the other side
* check out that header
*/
while(zmodem_data_waiting(zm, zm->consecutive_errors ? 1:0)
&& !is_cancelled(zm) && is_connected(zm)) {
int rx_type;
int c;
lprintf(zm, LOG_DEBUG, "Back-channel traffic detected");
if((c = zmodem_recv_raw(zm)) < 0) {
lprintf(zm, LOG_ERR, "Back-channel receive ERROR: %s", chr(c));
return(c);
}
if(c == ZPAD) {
/* ZMODEM.DOC:
FULL STREAMING WITH SAMPLING
If one of these characters (CAN or ZPAD) is seen, an
empty ZCRCE data subpacket is sent.
*/
zmodem_send_data(zm, ZCRCE, NULL, 0);
rx_type = zmodem_recv_header(zm);
lprintf(zm,LOG_DEBUG, "Received back-channel data: %s", chr(rx_type));
if(rx_type >= 0) {
return rx_type;
}
} else
lprintf(zm,LOG_INFO, "Unexpected back-channel data received: %s", chr(c));
}
if(is_cancelled(zm))
return(ZCAN);
zm->consecutive_errors = 0; zm->consecutive_errors = 0;
...@@ -1820,11 +1864,11 @@ BOOL zmodem_send_file(zmodem_t* zm, char* fname, FILE* fp, BOOL request_init, ti ...@@ -1820,11 +1864,11 @@ BOOL zmodem_send_file(zmodem_t* zm, char* fname, FILE* fp, BOOL request_init, ti
lprintf(zm,LOG_DEBUG,"Sending ZFILE frame: '%s'" lprintf(zm,LOG_DEBUG,"Sending ZFILE frame: '%s'"
,zm->tx_data_subpacket+strlen((char*)zm->tx_data_subpacket)+1); ,zm->tx_data_subpacket+strlen((char*)zm->tx_data_subpacket)+1);
if((i=zmodem_send_bin_header(zm,zfile_frame))!=0) { if((i=zmodem_send_bin_header(zm,zfile_frame)) != SEND_SUCCESS) {
lprintf(zm,LOG_DEBUG,"zmodem_send_bin_header returned %d",i); lprintf(zm,LOG_DEBUG,"zmodem_send_bin_header returned %d",i);
continue; continue;
} }
if((i=zmodem_send_data_subpkt(zm,ZCRCW,zm->tx_data_subpacket,p - zm->tx_data_subpacket))!=0) { if((i=zmodem_send_data_subpkt(zm,ZCRCW,zm->tx_data_subpacket,p - zm->tx_data_subpacket)) != SEND_SUCCESS) {
lprintf(zm,LOG_DEBUG,"zmodem_send_data_subpkt returned %d",i); lprintf(zm,LOG_DEBUG,"zmodem_send_data_subpkt returned %d",i);
continue; continue;
} }
...@@ -1905,15 +1949,16 @@ BOOL zmodem_send_file(zmodem_t* zm, char* fname, FILE* fp, BOOL request_init, ti ...@@ -1905,15 +1949,16 @@ BOOL zmodem_send_file(zmodem_t* zm, char* fname, FILE* fp, BOOL request_init, ti
if(type == ZRINIT) if(type == ZRINIT)
return(TRUE); /* Success */ return(TRUE); /* Success */
if(type == ZACK && zmodem_handle_zack(zm)) { pos = zm->ack_file_pos;
pos += sent_bytes;
if(type == ZACK && zmodem_handle_zack(zm, pos, zm->current_file_pos)) {
continue; continue;
} }
/* Error of some kind */ /* Error of some kind */
zm->errors++; zm->errors++;
lprintf(zm, LOG_ERR, "%lu ERROR #%d: Received %s", (ulong)zm->current_file_pos, zm->errors, chr(type)); lprintf(zm, LOG_ERR, "%lu ERROR #%d: %s", (ulong)zm->current_file_pos, zm->errors, chr(type));
if(zm->block_size == zm->max_block_size && zm->max_block_size > ZBLOCKLEN) if(zm->block_size == zm->max_block_size && zm->max_block_size > ZBLOCKLEN)
zm->max_block_size /= 2; zm->max_block_size /= 2;
...@@ -2338,9 +2383,7 @@ const char* zmodem_source(void) ...@@ -2338,9 +2383,7 @@ const char* zmodem_source(void)
char* zmodem_ver(char *buf) char* zmodem_ver(char *buf)
{ {
sscanf("$Revision: 1.124 $", "%*s %s", buf); return strcpy(buf, "2.0");
return(buf);
} }
void zmodem_init(zmodem_t* zm, void* cbdata void zmodem_init(zmodem_t* zm, void* cbdata
...@@ -2363,6 +2406,7 @@ void zmodem_init(zmodem_t* zm, void* cbdata ...@@ -2363,6 +2406,7 @@ void zmodem_init(zmodem_t* zm, void* cbdata
zm->block_size=ZBLOCKLEN; zm->block_size=ZBLOCKLEN;
zm->max_block_size=ZBLOCKLEN; zm->max_block_size=ZBLOCKLEN;
zm->max_errors=9; zm->max_errors=9;
zm->can_full_duplex=TRUE;
zm->cbdata=cbdata; zm->cbdata=cbdata;
zm->lputs=lputs; zm->lputs=lputs;
......
...@@ -281,6 +281,7 @@ typedef struct { ...@@ -281,6 +281,7 @@ typedef struct {
int32_t crc_request; int32_t crc_request;
unsigned errors; unsigned errors;
unsigned consecutive_errors; unsigned consecutive_errors;
int64_t current_window_size; /* "current transmitter file offset - last reported receiver file offset" */
/* Configuration */ /* Configuration */
BOOL escape_telnet_iac; BOOL escape_telnet_iac;
...@@ -292,6 +293,8 @@ typedef struct { ...@@ -292,6 +293,8 @@ typedef struct {
unsigned block_size; unsigned block_size;
unsigned max_block_size; unsigned max_block_size;
int64_t max_file_size; /* 0 = unlimited */ int64_t max_file_size; /* 0 = unlimited */
int64_t max_window_size; /* 0 = unlimited */
unsigned target_window_size; /* Target Transmit Window Size, in Seconds, 0 = no-auto-adjustment of window size */
int *log_level; int *log_level;
/* Callbacks */ /* Callbacks */
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment