The zmodem transmitter now uses buffered output

This commit is contained in:
Michiel Broek 2006-02-20 20:36:15 +00:00
parent 8a8306083a
commit fcdbbbbd6d
6 changed files with 159 additions and 181 deletions

View File

@ -26,6 +26,7 @@ v0.83.13 13-Feb-2006
Changed zmodem transmitter timeout to 60 seconds and changed Changed zmodem transmitter timeout to 60 seconds and changed
the zmodem init fase so that clients that don't start automatic the zmodem init fase so that clients that don't start automatic
have a chance to start the transfer. have a chance to start the transfer.
The zmodem transmitter now uses buffered output.
mbcico: mbcico:
Added real error message for failed outgoing IP connections. Added real error message for failed outgoing IP connections.

View File

@ -3,7 +3,7 @@
* $Id$ * $Id$
* *
***************************************************************************** *****************************************************************************
* Copyright (C) 1997-2005 * Copyright (C) 1997-2006
* *
* Michiel Broek FIDO: 2:280/2802 * Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10 * Beekmansbos 10
@ -53,6 +53,7 @@ struct tchars oldtch, tch;
int hanged_up = 0; int hanged_up = 0;
unsigned Baudrate = 2400; unsigned Baudrate = 2400;
int current_mode = -1;
/* Next is on compile commandline in lrzsz */ /* Next is on compile commandline in lrzsz */
#define NFGVMIN 1 #define NFGVMIN 1
@ -178,11 +179,18 @@ void hangup(void)
* 1: save old tty stat, set raw mode * 1: save old tty stat, set raw mode
* 0: restore original tty mode * 0: restore original tty mode
*/ */
char *io_names[] = { (char *)"restore-tty", (char *)"save-tty set-raw", (char *)"set-Xon/Xoff", (char *)"save-tty set-raw-flow" };
int io_mode(int fd, int n) int io_mode(int fd, int n)
{ {
static int did0 = FALSE; static int did0 = FALSE;
Syslog('t', "io_mode(%d, %d)", fd, n); Syslog('t', "io_mode(%d, %d) (%s)", fd, n, io_names[n]);
if (n == current_mode) {
Syslog('t', "io_mode already set");
return 0;
}
current_mode = n;
switch(n) { switch(n) {
@ -199,7 +207,7 @@ int io_mode(int fd, int n)
tty.c_oflag = 0; /* Transparent output */ tty.c_oflag = 0; /* Transparent output */
tty.c_cflag &= ~PARENB; /* Disable parity */ tty.c_cflag &= ~PARENB; /* Disable parity */
tty.c_cflag |= CS8; /* Set character size = 8 */ tty.c_cflag |= (CS8 & CRTSCTS); /* Set character size = 8 and xon/xoff */
#ifdef READCHECK #ifdef READCHECK
tty.c_lflag = protocol==ZM_ZMODEM ? 0 : ISIG; tty.c_lflag = protocol==ZM_ZMODEM ? 0 : ISIG;
tty.c_cc[VINTR] = protocol==ZM_ZMODEM ? -1 : 030; /* Interrupt char */ tty.c_cc[VINTR] = protocol==ZM_ZMODEM ? -1 : 030; /* Interrupt char */
@ -338,8 +346,11 @@ int io_mode(int fd, int n)
tty = oldtty; tty = oldtty;
tty.c_iflag = IGNBRK; tty.c_iflag = IGNBRK;
if (n == 3) /* with flow control */ if (n == 3) { /* with flow control */
tty.c_iflag |= IXOFF; tty.c_iflag |= IXOFF;
tty.c_cflag |= CRTSCTS;
}
/* /*
* Setup raw mode: no echo, noncanonical (no edit chars), * Setup raw mode: no echo, noncanonical (no edit chars),

View File

@ -50,7 +50,7 @@
* *
*/ */
static void zputhex(int, char *); static void zputhex(int);
static void zsbh32(char*, int); static void zsbh32(char*, int);
static void zsda32(char*, int, int); static void zsda32(char*, int, int);
static int zrdat32(char*,int); static int zrdat32(char*,int);
@ -61,7 +61,6 @@ static int zrhhdr(char*);
static int zgethex(void); static int zgethex(void);
static int zgeth1(void); static int zgeth1(void);
static void garbitch(void); static void garbitch(void);
static inline void zsendline_s(const char *, int);
#include "../config.h" #include "../config.h"
#include "../lib/mbselib.h" #include "../lib/mbselib.h"
@ -79,7 +78,6 @@ char *txbuf=NULL;
static int lastsent; /* Last char we sent */ static int lastsent; /* Last char we sent */
static int Not8bit; /* Seven bits seen on header */ static int Not8bit; /* Seven bits seen on header */
static char zsendline_tab[256];
extern unsigned Baudrate; extern unsigned Baudrate;
extern int zmodem_requested; extern int zmodem_requested;
@ -128,9 +126,43 @@ char *frametypes[] = {
}; };
/***** Hack by mj ***********************************************************/
/*
* Buffer for outgoing frames. Sending them with single character write()'s
* is a waste of processor time and causes severe performance degradation
* on TCP and ISDN connections.
*/
#define FRAME_BUFFER_SIZE 16384
static char *frame_buffer=NULL;
static int frame_length = 0;
#define BUFFER_CLEAR() do { frame_length=0; } while(0)
#define BUFFER_BYTE(c) do { frame_buffer[frame_length++]=(c); } while(0)
#define BUFFER_FLUSH() do { PUT(frame_buffer, frame_length); frame_length=0; } while(0);
/****************************************************************************/ /****************************************************************************/
void get_frame_buffer(void)
{
if (frame_buffer == NULL)
frame_buffer=xmalloc(FRAME_BUFFER_SIZE);
}
void del_frame_buffer(void)
{
if (frame_buffer == NULL)
return;
free(frame_buffer);
frame_buffer = NULL;
}
/* /*
* Send ZMODEM binary header hdr of type type * Send ZMODEM binary header hdr of type type
*/ */
@ -141,17 +173,19 @@ void zsbhdr(int type, char *shdr)
Syslog('z', "zsbhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(shdr)); Syslog('z', "zsbhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(shdr));
BUFFER_CLEAR();
if (type == ZDATA) if (type == ZDATA)
for (n = Znulls; --n >=0; ) for (n = Znulls; --n >=0; )
PUTCHAR(0); BUFFER_BYTE(0);
PUTCHAR(ZPAD); BUFFER_BYTE(ZPAD);
PUTCHAR(ZDLE); BUFFER_BYTE(ZDLE);
if ((Crc32t = Txfcs32)) if ((Crc32t = Txfcs32))
zsbh32(shdr, type); zsbh32(shdr, type);
else { else {
PUTCHAR(ZBIN); BUFFER_BYTE(ZBIN);
zsendline(type); zsendline(type);
crc = updcrc16(type, 0); crc = updcrc16(type, 0);
@ -164,8 +198,7 @@ void zsbhdr(int type, char *shdr)
zsendline(crc); zsendline(crc);
} }
if (type != ZDATA) BUFFER_FLUSH();
fflush(stdout);
} }
@ -178,7 +211,7 @@ void zsbh32(char *shdr, int type)
register int n; register int n;
register unsigned int crc; register unsigned int crc;
PUTCHAR(ZBIN32); BUFFER_BYTE(ZBIN32);
zsendline(type); zsendline(type);
crc = 0xFFFFFFFFL; crc = 0xFFFFFFFFL;
crc = updcrc32(type, crc); crc = updcrc32(type, crc);
@ -203,44 +236,41 @@ void zshhdr(int type, char *shdr)
{ {
register int n; register int n;
register unsigned short crc; register unsigned short crc;
char s[30];
size_t len;
Syslog('z', "zshhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(shdr)); Syslog('z', "zshhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(shdr));
s[0]=ZPAD; BUFFER_CLEAR();
s[1]=ZPAD;
s[2]=ZDLE; BUFFER_BYTE(ZPAD);
s[3]=ZHEX; BUFFER_BYTE(ZPAD);
zputhex(type & 0x7f, s+4); BUFFER_BYTE(ZDLE);
len = 6; BUFFER_BYTE(ZHEX);
zputhex(type & 0x7f);
Crc32t = 0; Crc32t = 0;
crc = updcrc16((type & 0x7f), 0); crc = updcrc16((type & 0x7f), 0);
for (n=4; --n >= 0; ++shdr) { for (n=4; --n >= 0; ++shdr) {
zputhex(*shdr, s+len); zputhex(*shdr);
len += 2;
crc = updcrc16((0377 & *shdr), crc); crc = updcrc16((0377 & *shdr), crc);
} }
crc = updcrc16(0,updcrc16(0,crc)); crc = updcrc16(0,updcrc16(0,crc));
zputhex((int)(crc>>8), s+len); zputhex((int)(crc>>8));
zputhex((int)(crc & 0xff), s+len+2); zputhex((int)(crc & 0xff));
len += 4;
/* /*
* Make it printable on remote machine * Make it printable on remote machine
*/ */
s[len++]=015; BUFFER_BYTE(015);
s[len++]=0212; BUFFER_BYTE(0212);
/* /*
* Uncork the remote in case a fake XOFF has stopped data flow * Uncork the remote in case a fake XOFF has stopped data flow
*/ */
if (type != ZFIN && type != ZACK) if (type != ZFIN && type != ZACK)
s[len++]=021; BUFFER_BYTE(021);
PUT(s, len); BUFFER_FLUSH();
fflush(stdout);
} }
@ -253,6 +283,8 @@ void zsdata(register char *buf, int length, int frameend)
{ {
register unsigned short crc; register unsigned short crc;
BUFFER_CLEAR();
if (Crc32t) if (Crc32t)
zsda32(buf, length, frameend); zsda32(buf, length, frameend);
else { else {
@ -262,8 +294,8 @@ void zsdata(register char *buf, int length, int frameend)
zsendline(*buf); zsendline(*buf);
crc = updcrc16((0377 & *buf), crc); crc = updcrc16((0377 & *buf), crc);
} }
PUTCHAR(ZDLE); BUFFER_BYTE(ZDLE);
PUTCHAR(frameend); BUFFER_BYTE(frameend);
crc = updcrc16(frameend, crc); crc = updcrc16(frameend, crc);
crc = updcrc16(0,updcrc16(0,crc)); crc = updcrc16(0,updcrc16(0,crc));
@ -271,45 +303,40 @@ void zsdata(register char *buf, int length, int frameend)
zsendline(crc); zsendline(crc);
} }
if (frameend == ZCRCW) { if (frameend == ZCRCW)
PUTCHAR(XON); BUFFER_BYTE(XON);
fflush(stdout);
} BUFFER_FLUSH();
} }
void zsda32(register char *buf, int length, int frameend) void zsda32(register char *buf, int length, int frameend)
{ {
int c, i; int c;
unsigned int crc; unsigned int crc;
Syslog('z', "zsdat32: %d %s", length, Zendnames[(frameend-ZCRCE)&3]); Syslog('z', "zsdat32: %d %s", length, Zendnames[(frameend-ZCRCE)&3]);
crc = 0xFFFFFFFFL; crc = 0xFFFFFFFFL;
zsendline_s(buf, length);
for (;--length >= 0; ++buf) { for (;--length >= 0; ++buf) {
c = *buf & 0377; c = *buf & 0377;
zsendline(*buf);
crc = updcrc32(c, crc); crc = updcrc32(c, crc);
} }
PUTCHAR(ZDLE); BUFFER_BYTE(ZDLE);
PUTCHAR(frameend); BUFFER_BYTE(frameend);
crc = updcrc32(frameend, crc); crc = updcrc32(frameend, crc);
crc = ~crc; crc = ~crc;
for (i=4; --i >= 0;) { for (c=4; --c >= 0;) {
c = (int) crc; zsendline((int)crc); crc >>= 8;
if (c & 0140)
PUTCHAR(lastsent = c);
else
zsendline(c);
crc >>= 8;
} }
if (frameend == ZCRCW) { // if (frameend == ZCRCW) {
PUTCHAR(XON); // BUFFER_BYTE(XON);
fflush(stdout); // fflush(stdout);
} // }
} }
@ -405,7 +432,7 @@ crcfoo:
goto crcfoo; goto crcfoo;
crc = updcrc32(c, crc); crc = updcrc32(c, crc);
if (crc != 0xDEBB20E3) { if (crc != 0xDEBB20E3) {
Syslog('+', "Zmodem zrdat32: Bad CRC"); Syslog('+', "Zmodem zrdat32: Bad CRC %08x should be 0xDEBB20E3", crc);
return TERROR; return TERROR;
} }
Rxcount = length - (end - buf); Rxcount = length - (end - buf);
@ -449,15 +476,16 @@ void garbitch(void)
*/ */
int zgethdr(char *shdr) int zgethdr(char *shdr)
{ {
register int c, n, cancount; register int c, n, cancount, tmcount;
int Zrwindow = 1400; // int Zrwindow = 1400;
int Zrwindow = 1024;
n = Zrwindow + Baudrate; n = Zrwindow + Baudrate;
Rxframeind = Rxtype = 0; Rxframeind = Rxtype = 0;
startover: startover:
cancount = 5; cancount = 5;
tmcount = 5;
again: again:
/* /*
* Return immediate ERROR if ZCRCW sequence seen * Return immediate ERROR if ZCRCW sequence seen
@ -468,18 +496,23 @@ again:
switch(c) { switch(c) {
case 021: case 021:
case 0221: goto again; case 0221: goto again;
case HANGUP: case HANGUP: goto fifi;
case TIMEOUT: goto fifi; case TIMEOUT: Syslog('z', "zgethdr: got TIMEOUT %d", tmcount);
if (--tmcount <= 0) {
c = TERROR;
goto fifi;
}
goto startover;
case CAN: case CAN:
gotcan: gotcan:
Syslog('z', "zgethdr: got CAN"); Syslog('z', "zgethdr: got CAN %d", cancount);
if (--cancount <= 0) { if (--cancount <= 0) {
c = ZCAN; c = ZCAN;
goto fifi; goto fifi;
} }
switch (c = GETCHAR(Rxtimeout)) { switch (c = GETCHAR(1)) {
case TIMEOUT: goto again; case TIMEOUT: goto again;
case ZCRCW: switch (GETCHAR(Rxtimeout)) { case ZCRCW: switch (GETCHAR(1)) {
case TIMEOUT: c = TERROR; case TIMEOUT: c = TERROR;
goto fifi; goto fifi;
case HANGUP: goto fifi; case HANGUP: goto fifi;
@ -669,7 +702,7 @@ int zrhhdr(char *shdr)
return TERROR; return TERROR;
} }
switch (c = GETCHAR(Rxtimeout)) { switch (c = GETCHAR(2)) {
case 0215: Not8bit = c; case 0215: Not8bit = c;
/* **** FALL THRU TO **** */ /* **** FALL THRU TO **** */
case 015: /* Throw away possible cr/lf */ case 015: /* Throw away possible cr/lf */
@ -690,13 +723,14 @@ int zrhhdr(char *shdr)
/* /*
* Send a byte as two hex digits * Send a byte as two hex digits
*/ */
void zputhex(int c, char *pos) void zputhex(int c)
{ {
static char digits[] = "0123456789abcdef"; static char digits[] = "0123456789abcdef";
Syslog('z', "zputhex: %02x", c); Syslog('z', "zputhex: %02x", c);
pos[0] = digits[(c & 0xF0) >> 4];
pos[1] = digits[c & 0xF]; BUFFER_BYTE(digits[(c&0xF0)>>4]);
BUFFER_BYTE(digits[(c)&0xF]);
} }
@ -707,112 +741,38 @@ void zputhex(int c, char *pos)
*/ */
void zsendline(int c) void zsendline(int c)
{ {
switch(zsendline_tab[(unsigned) (c&=0377)]) { /* Quick check for non control characters */
case 0: if (c & 0140)
PUTCHAR(lastsent = c); BUFFER_BYTE(lastsent = c);
break; else {
case 1: switch (c &= 0377) {
PUTCHAR(ZDLE); case ZDLE:
c ^= 0100; BUFFER_BYTE(ZDLE);
PUTCHAR(lastsent = c); BUFFER_BYTE (lastsent = (c ^= 0100));
break;
case 2:
if ((lastsent & 0177) != '@') {
PUTCHAR(lastsent = c);
} else {
PUTCHAR(ZDLE);
c ^= 0100;
PUTCHAR(lastsent = c);
}
break;
}
}
static inline void zsendline_s(const char *s, int count)
{
const char *end = s + count;
while (s != end) {
int last_esc = 0;
const char *t = s;
while (t != end) {
last_esc = zsendline_tab[(unsigned) ((*t) & 0377)];
if (last_esc)
break;
t++;
}
if (t != s) {
PUT((char *)s, (t-s));
lastsent = t[-1];
s = t;
}
if (last_esc) {
int c = *s;
switch (last_esc) {
case 0:
PUTCHAR(lastsent = c);
break; break;
case 1: case 015:
PUTCHAR(ZDLE); case 0215:
if (!Zctlesc && (lastsent & 0177) != '@')
goto sendit;
/* **** FALL THRU TO **** */
case 020:
case 021:
case 023:
case 0220:
case 0221:
case 0223:
BUFFER_BYTE(ZDLE);
c ^= 0100; c ^= 0100;
PUTCHAR(lastsent = c); sendit:
BUFFER_BYTE(lastsent = c);
break; break;
case 2: default:
if ((lastsent & 0177) != '@') { if (Zctlesc && ! (c & 0140)) {
PUTCHAR(lastsent = c); BUFFER_BYTE(ZDLE);
} else {
PUTCHAR(ZDLE);
c ^= 0100; c ^= 0100;
PUTCHAR(lastsent = c);
} }
break; BUFFER_BYTE(lastsent = c);
}
s++;
}
}
}
void zsendline_init(void)
{
int i;
Syslog('z', "zsendline_init()");
for (i = 0; i < 256; i++) {
if (i & 0140)
zsendline_tab[i]=0;
else {
switch(i) {
case ZDLE:
case XOFF: /* ^Q */
case XON: /* ^S */
case (XOFF | 0200):
case (XON | 0200):
zsendline_tab[i]=1;
break;
case 020: /* ^P */
case 0220:
zsendline_tab[i]=1;
break;
case 015:
case 0215:
if (Zctlesc)
zsendline_tab[i]=1;
else
zsendline_tab[i]=2;
break;
default:
if (Zctlesc)
zsendline_tab[i]=1;
else
zsendline_tab[i]=0;
}
} }
} }
} }

View File

@ -145,7 +145,8 @@ enum zm_type_enum {
enum zm_type_enum protocol; enum zm_type_enum protocol;
void get_frame_buffer(void);
void del_frame_buffer(void);
void zsbhdr(int, char *); void zsbhdr(int, char *);
void zshhdr(int, char *); void zshhdr(int, char *);
void zsdata(register char *, int, int); void zsdata(register char *, int, int);
@ -157,7 +158,6 @@ void zsendline(int);
int zdlread(void); int zdlread(void);
void stohdr(int); void stohdr(int);
int rclhdr(register char *); int rclhdr(register char *);
void zsendline_init(void);
char *protname(void); char *protname(void);
void purgeline(int); void purgeline(int);
void canit(int); void canit(int);

View File

@ -4,7 +4,7 @@
* Purpose ...............: Zmodem receive * Purpose ...............: Zmodem receive
* *
***************************************************************************** *****************************************************************************
* Copyright (C) 1997-2005 * Copyright (C) 1997-2006
* *
* Michiel Broek FIDO: 2:280/2802 * Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10 * Beekmansbos 10
@ -87,8 +87,9 @@ int zmrcvfiles(int want1k, int wantg)
Syslog('+', "%s: start receive", protname()); Syslog('+', "%s: start receive", protname());
get_frame_buffer();
Rxtimeout = 10; Rxtimeout = 10;
zsendline_init();
if (secbuf == NULL) if (secbuf == NULL)
secbuf = malloc(MAXBLOCK+1); secbuf = malloc(MAXBLOCK+1);
tryzhdrtype = ZRINIT; tryzhdrtype = ZRINIT;

View File

@ -4,7 +4,7 @@
* Purpose ...............: Zmodem sender * Purpose ...............: Zmodem sender
* *
***************************************************************************** *****************************************************************************
* Copyright (C) 1997-2005 * Copyright (C) 1997-2006
* *
* Michiel Broek FIDO: 2:280/2802 * Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10 * Beekmansbos 10
@ -88,15 +88,18 @@ int zmsndfiles(down_list *lst, int try8)
down_list *tmpf; down_list *tmpf;
Syslog('+', "Zmodem: start Zmodem%s send", try8 ? "-8K":""); Syslog('+', "Zmodem: start Zmodem%s send", try8 ? "-8K":"");
get_frame_buffer();
use8k = try8; use8k = try8;
protocol = ZM_ZMODEM; protocol = ZM_ZMODEM;
zsendline_init();
Rxtimeout = 60; Rxtimeout = 60;
if ((rc = initsend())) { if ((rc = initsend())) {
if (txbuf) if (txbuf)
free(txbuf); free(txbuf);
txbuf = NULL; txbuf = NULL;
del_frame_buffer();
return abs(rc); return abs(rc);
} }
@ -128,6 +131,7 @@ int zmsndfiles(down_list *lst, int try8)
if (txbuf) if (txbuf)
free(txbuf); free(txbuf);
txbuf = NULL; txbuf = NULL;
del_frame_buffer();
io_mode(0, 1); io_mode(0, 1);
Syslog('z', "Zmodem: send rc=%d", maxrc); Syslog('z', "Zmodem: send rc=%d", maxrc);
@ -258,14 +262,14 @@ int getzrxinit(void)
case ZRINIT: case ZRINIT:
Rxflags = 0377 & Rxhdr[ZF0]; Rxflags = 0377 & Rxhdr[ZF0];
Txfcs32 = (Wantfcs32 && (Rxflags & CANFC32)); Txfcs32 = (Wantfcs32 && (Rxflags & CANFC32));
{ // {
int old = Zctlesc; // int old = Zctlesc;
Zctlesc |= Rxflags & TESCCTL; Zctlesc |= Rxflags & TESCCTL;
/* update table - was initialised to not escape */ // /* update table - was initialised to not escape */
if (Zctlesc && !old) // if (Zctlesc && !old)
zsendline_init(); // zsendline_init();
} // }
Rxbuflen = (0377 & Rxhdr[ZP0])+((0377 & Rxhdr[ZP1])<<8); Rxbuflen = (0377 & Rxhdr[ZP0])+((0377 & Rxhdr[ZP1])<<8);
if ( !(Rxflags & CANFDX)) if ( !(Rxflags & CANFDX))
Txwindow = 0; Txwindow = 0;
@ -428,6 +432,7 @@ again:
* Suppress zcrcw request otherwise triggered by * Suppress zcrcw request otherwise triggered by
* lastyunc==bytcnt * lastyunc==bytcnt
*/ */
Syslog('z', "got ZRPOS %d", Rxpos);
if (Rxpos > 0) if (Rxpos > 0)
skipsize = Rxpos; skipsize = Rxpos;
if (fseek(in, Rxpos, 0)) if (fseek(in, Rxpos, 0))