--- sbbs/src/sbbs3/sexyz.c 2018/04/24 16:41:23 1.1 +++ sbbs/src/sbbs3/sexyz.c 2018/04/24 16:43:07 1.1.1.2 @@ -2,13 +2,13 @@ /* Synchronet External X/Y/ZMODEM Transfer Protocols */ -/* $Id: sexyz.c,v 1.1 2018/04/24 16:41:23 root Exp $ */ +/* $Id: sexyz.c,v 1.1.1.2 2018/04/24 16:43:07 root Exp $ */ /**************************************************************************** * @format.tab-size 4 (Plain Text/Source Code File Header) * * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * * * - * Copyright 2006 Rob Swindell - http://www.synchro.net/copyright.html * + * Copyright 2011 Rob Swindell - http://www.synchro.net/copyright.html * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * @@ -77,19 +77,23 @@ #define SINGLE_THREADED FALSE #define MIN_OUTBUF_SIZE 1024 #define MAX_OUTBUF_SIZE (64*1024) +#define INBUF_SIZE (64*1024) +#define MAX_FILE_SIZE 0 /* Default value for max recv file size, 0 = unlimited*/ /***************/ /* Global Vars */ /***************/ long mode=0; /* Program mode */ long zmode=0L; /* Zmodem mode */ -uchar block[1024]; /* Block buffer */ +uchar block[XMODEM_MAX_BLOCK_SIZE]; /* Block buffer */ ulong block_num; /* Block number */ char* dszlog; BOOL dszlog_path=TRUE; /* Log complete path to filename */ BOOL dszlog_short=FALSE; /* Log Micros~1 short filename */ BOOL dszlog_quotes=FALSE; /* Quote filenames in DSZLOG */ int log_level=LOG_INFO; +BOOL use_syslog=FALSE; +int64_t max_file_size=MAX_FILE_SIZE; xmodem_t xm; zmodem_t zm; @@ -105,9 +109,7 @@ SOCKET sock=INVALID_SOCKET; BOOL telnet=TRUE; #ifdef __unix__ BOOL stdio=FALSE; -struct termios origterm; #endif -BOOL aborted=FALSE; BOOL terminate=FALSE; BOOL debug_tx=FALSE; BOOL debug_rx=FALSE; @@ -115,6 +117,7 @@ BOOL debug_telnet=FALSE; BOOL pause_on_exit=FALSE; BOOL pause_on_abend=FALSE; BOOL newline=TRUE; +BOOL connected=TRUE; time_t progress_interval; @@ -127,16 +130,13 @@ RingBuf outbuf; unsigned outbuf_drain_timeout; long outbuf_size; +uchar inbuf[INBUF_SIZE]; +unsigned inbuf_pos=0; +unsigned inbuf_len=0; + unsigned flows=0; unsigned select_errors=0; -#ifdef __unix__ -void resetterm(void) -{ - tcsetattr(STDOUT_FILENO, TCSADRAIN, &origterm); -} -#endif - #ifdef _WINSOCKAPI_ /* Note: Don't call WSACleanup() or TCP session will close! */ @@ -164,6 +164,7 @@ static BOOL winsock_startup(void) static int lputs(void* unused, int level, const char* str) { FILE* fp=statfp; + int ret; #if defined(_WIN32) && defined(_DEBUG) if(log_level==LOG_DEBUG) @@ -181,9 +182,24 @@ static int lputs(void* unused, int level newline=TRUE; } if(levellog_level) + return 0; + va_start(argptr,fmt); vsnprintf(sbuf,sizeof(sbuf),fmt,argptr); sbuf[sizeof(sbuf)-1]=0; @@ -203,7 +222,7 @@ void break_handler(int type) lprintf(LOG_NOTICE,"-> Aborted Locally (signal: %d)",type); /* Flag to indicate local (as opposed to remote) abort */ - aborted=TRUE; + zm.local_abort=TRUE; /* Stop any transfers in progress immediately */ xm.cancelled=TRUE; @@ -211,7 +230,7 @@ void break_handler(int type) } #if defined(_WIN32) -BOOL WINAPI ControlHandler(DWORD CtrlType) +BOOL WINAPI ControlHandler(unsigned long CtrlType) { break_handler((int)CtrlType); return TRUE; @@ -305,6 +324,61 @@ void dump(BYTE* buf, int len) } } +int sendbuf(SOCKET s, void *buf, size_t buflen) +{ + size_t sent=0; + int ret; + fd_set socket_set; + + for(;;) { +#ifdef __unix__ + if(stdio) + ret=write(STDOUT_FILENO, (char *)buf+sent,buflen-sent); + else +#endif + ret=sendsocket(s,(char *)buf+sent,buflen-sent); + if(ret==SOCKET_ERROR) { + switch(ERROR_VALUE) { + case EAGAIN: + case ENOBUFS: +#if (EAGAIN != EWOULDBLOCK) + case EWOULDBLOCK: +#endif + /* Block until we can send */ + FD_ZERO(&socket_set); +#ifdef __unix__ + if(stdio) + FD_SET(STDIN_FILENO,&socket_set); + else +#endif + FD_SET(sock,&socket_set); + + if((ret=select(sock+1,NULL,&socket_set,NULL,NULL))<1) { + if(ret==SOCKET_ERROR && ERROR_VALUE != EINTR) { + lprintf(LOG_ERR,"ERROR %d selecting socket", ERROR_VALUE); + goto disconnect; + } + } + break; + default: + goto disconnect; + } + } + else { + sent += ret; + if(sent >= buflen) + return(sent); + } + } + +disconnect: + lprintf(LOG_DEBUG,"DISCONNECTED line %u", __LINE__); + connected=FALSE; + if(sent) + return sent; + return SOCKET_ERROR; +} + void send_telnet_cmd(SOCKET sock, uchar cmd, uchar opt) { uchar buf[3]; @@ -317,55 +391,127 @@ void send_telnet_cmd(SOCKET sock, uchar lprintf(LOG_DEBUG,"Sending telnet command: %s %s" ,telnet_cmd_desc(buf[1]),telnet_opt_desc(buf[2])); - if(sendsocket(sock,buf,sizeof(buf))!=sizeof(buf) && debug_telnet) + if(sendbuf(sock,buf,sizeof(buf))!=sizeof(buf) && debug_telnet) lprintf(LOG_ERR,"FAILED"); } #define DEBUG_TELNET FALSE +/* + * Returns -1 on disconnect or the number of bytes read. + * Does not muck around with ERROR_VALUE (hopefully) + */ +static int recv_buffer(int timeout /* seconds */) +{ + int i; + fd_set socket_set; + struct timeval tv; + int magic_errno; + + for(;;) { + if(inbuf_len > inbuf_pos) + return(inbuf_len-inbuf_pos); +#ifdef __unix__ + if(stdio) { + i=read(STDIN_FILENO,inbuf,sizeof(inbuf)); + /* Look like a socket using MAGIC! */ + switch(i) { + case 0: + i=-1; + magic_errno=EAGAIN; + break; + case -1: + magic_errno=errno; + break; + } + } + else +#endif + { + i=recv(sock,inbuf,sizeof(inbuf),0); + if(i==SOCKET_ERROR) + magic_errno=ERROR_VALUE; + } + if(i==SOCKET_ERROR) { + switch(magic_errno) { + case EAGAIN: + case EINTR: +#if (EAGAIN != EWOULDBLOCK) + case EWOULDBLOCK: +#endif + // Call select() + if(timeout) { + FD_ZERO(&socket_set); +#ifdef __unix__ + if(stdio) + FD_SET(STDIN_FILENO,&socket_set); + else +#endif + FD_SET(sock,&socket_set); + tv.tv_sec=timeout; + timeout=0; + tv.tv_usec=0; + if((i=select(sock+1,&socket_set,NULL,NULL,&tv))<1) { + if(i==SOCKET_ERROR) { + lprintf(LOG_ERR,"ERROR %d selecting socket", magic_errno); + connected=FALSE; + } + else + lprintf(LOG_WARNING,"Receive timeout (%u seconds)", timeout); + } + else + continue; + } + return 0; + default: + lprintf(LOG_DEBUG,"DISCONNECTED line %u, error=%u", __LINE__,magic_errno); + connected=FALSE; + return -1; + } + return -1; // Impossible. + } + else if(i==0) { + lprintf(LOG_DEBUG,"DISCONNECTED line %u", __LINE__); + connected=FALSE; + return -1; + } + else { + inbuf_len=i; + return i; + } + }; +} + /****************************************************************************/ /* Receive a byte from remote (single-threaded version) */ /****************************************************************************/ -int recv_byte(void* unused, unsigned timeout) +int recv_byte(void* unused, unsigned timeout /* seconds */) { int i; - long t; uchar ch; - fd_set socket_set; - time_t end; - struct timeval tv; static uchar telnet_cmd; static int telnet_cmdlen; - end=msclock()+(timeout*MSCLOCKS_PER_SEC); - while(!terminate) { - - FD_ZERO(&socket_set); -#ifdef __unix__ - if(stdio) - FD_SET(STDIN_FILENO,&socket_set); - else -#endif - FD_SET(sock,&socket_set); - if((t=end-msclock())<0) t=0; - tv.tv_sec=t/MSCLOCKS_PER_SEC; - tv.tv_usec=0; - - if((i=select(sock+1,&socket_set,NULL,NULL,&tv))<1) { - if(i==SOCKET_ERROR) { - lprintf(LOG_ERR,"ERROR %d selecting socket", ERROR_VALUE); - } - if(timeout) - lprintf(LOG_WARNING,"Receive timeout (%u seconds)", timeout); - return(NOINP); + while((inbuf_len || connected) && !terminate) { + if(inbuf_len) { + ch=inbuf[inbuf_pos++]; + i=1; + if(inbuf_pos >= inbuf_len) + inbuf_pos=inbuf_len=0; + } + else { + i=recv_buffer(timeout); + switch(i) { + case -1: + i=0; + break; + case 0: + return NOINP; + default: + i=1; + continue; + } } - -#ifdef __unix__ - if(stdio) - i=read(STDIN_FILENO,&ch,sizeof(ch)); - else -#endif - i=recv(sock,&ch,sizeof(ch),0); if(i!=sizeof(ch)) { if(i==0) { @@ -441,24 +587,35 @@ int send_byte(void* unused, uchar ch, un buf[0]=ch; if(RingBufFree(&outbuf)sizeof(buf)) { lprintf(LOG_ERR,"Insufficient linear output buffer (%lu > %lu)" @@ -582,12 +694,7 @@ static void output_thread(void* arg) buftop=RingBufRead(&outbuf, buf, avail); bufbot=0; } -#ifdef __unix__ - if(stdio) - i=write(STDOUT_FILENO, (char*)buf+bufbot, buftop-bufbot); - else -#endif - i=sendsocket(sock, (char*)buf+bufbot, buftop-bufbot); + i=sendbuf(sock, (char*)buf+bufbot, buftop-bufbot); if(i==SOCKET_ERROR) { if(ERROR_VALUE == ENOTSOCK) lprintf(LOG_ERR,"client socket closed on send"); @@ -615,7 +722,7 @@ static void output_thread(void* arg) } if(total_sent) - sprintf(stats,"(sent %lu bytes in %lu blocks, %lu average, %lu short, %lu errors)" + sprintf(stats,"(sent %"PRIu64" bytes in %"PRIu64" blocks, %"PRIu64" average, %lu short, %lu errors)" ,total_sent, total_pkts, total_sent/total_pkts, short_sends, select_errors); else stats[0]=0; @@ -623,29 +730,39 @@ static void output_thread(void* arg) lprintf(LOG_DEBUG,"output thread terminated\n%s", stats); } -BOOL is_connected(void* unused) +/* Flush output buffer */ +void flush(void* unused) { - return socket_check(sock,NULL,NULL,0); +#ifdef __unix__ + if(stdio) + fflush(stdout); +#endif } -BOOL data_waiting(void* unused, unsigned timeout) +BOOL is_connected(void* unused) { - BOOL rd; + if(inbuf_len > inbuf_pos) + return TRUE; + return connected; +} - if(!socket_check(sock,&rd,NULL,timeout)) - return(FALSE); - return(rd); +BOOL data_waiting(void* unused, unsigned timeout /* seconds */) +{ + if(recv_buffer(timeout) > 0) + return TRUE; + return FALSE; } /****************************************************************************/ -/* Returns the number of blocks required to send len bytes */ +/* Returns the total number of blocks required to send the file */ /****************************************************************************/ -unsigned num_blocks(ulong len, unsigned block_size) +uint64_t num_blocks(unsigned block_num, uint64_t offset, uint64_t len, unsigned block_size) { - ulong blocks; + uint64_t blocks; + uint64_t remain = len - offset; - blocks=len/block_size; - if(len%block_size) + blocks=block_num + (remain/block_size); + if(remain%block_size) blocks++; return(blocks); } @@ -662,10 +779,10 @@ void dump_block(long block_size) fprintf(statfp,"\n"); } -void xmodem_progress(void* unused, unsigned block_num, ulong offset, ulong fsize, time_t start) +void xmodem_progress(void* unused, unsigned block_num, int64_t offset, int64_t fsize, time_t start) { unsigned cps; - unsigned total_blocks; + uint64_t total_blocks; long l; long t; time_t now; @@ -676,14 +793,14 @@ void xmodem_progress(void* unused, unsig t=now-start; if(t<=0) t=1; - if((cps=offset/t)==0) - cps=1; /* cps so far */ - l=fsize/cps; /* total transfer est time */ - l-=t; /* now, it's est time left */ + if((cps=(unsigned)(offset/t))==0) + cps=1; /* cps so far */ + l=(long)(fsize/cps); /* total transfer est time */ + l-=t; /* now, it's est time left */ if(l<0) l=0; if(mode&SEND) { - total_blocks=num_blocks(fsize,xm.block_size); - fprintf(statfp,"\rBlock (%lu%s): %lu/%lu Byte: %lu " + total_blocks=num_blocks(block_num,offset,fsize,xm.block_size); + fprintf(statfp,"\rBlock (%lu%s): %lu/%"PRId64" Byte: %"PRId64" " "Time: %lu:%02lu/%lu:%02lu %u cps %lu%% " ,xm.block_size%1024L ? xm.block_size: xm.block_size/1024L ,xm.block_size%1024L ? "" : "K" @@ -695,10 +812,10 @@ void xmodem_progress(void* unused, unsig ,l/60L ,l%60L ,cps - ,(long)(((float)offset/(float)fsize)*100.0) + ,fsize?(long)(((float)offset/(float)fsize)*100.0):100 ); } else if(mode&YMODEM) { - fprintf(statfp,"\rBlock (%lu%s): %lu Byte: %lu " + fprintf(statfp,"\rBlock (%lu%s): %lu Byte: %"PRId64" " "Time: %lu:%02lu/%lu:%02lu %u cps %lu%% " ,xm.block_size%1024L ? xm.block_size: xm.block_size/1024L ,xm.block_size%1024L ? "" : "K" @@ -709,10 +826,10 @@ void xmodem_progress(void* unused, unsig ,l/60L ,l%60L ,cps - ,(long)(((float)offset/(float)fsize)*100.0) + ,fsize?(long)(((float)offset/(float)fsize)*100.0):100 ); } else { /* XModem receive */ - fprintf(statfp,"\rBlock (%lu%s): %lu Byte: %lu " + fprintf(statfp,"\rBlock (%lu%s): %lu Byte: %"PRId64" " "Time: %lu:%02lu %u cps " ,xm.block_size%1024L ? xm.block_size: xm.block_size/1024L ,xm.block_size%1024L ? "" : "K" @@ -732,7 +849,7 @@ void xmodem_progress(void* unused, unsig * show the progress of the transfer like this: * zmtx: sending file "garbage" 4096 bytes ( 20%) */ -void zmodem_progress(void* cbdata, ulong current_pos) +void zmodem_progress(void* cbdata, int64_t current_pos) { unsigned cps; long l; @@ -747,12 +864,12 @@ void zmodem_progress(void* cbdata, ulong t=1; if(zm.transfer_start_pos>current_pos) zm.transfer_start_pos=0; - if((cps=(current_pos-zm.transfer_start_pos)/t)==0) - cps=1; /* cps so far */ - l=zm.current_file_size/cps; /* total transfer est time */ - l-=t; /* now, it's est time left */ + if((cps=(unsigned)((current_pos-zm.transfer_start_pos)/t))==0) + cps=1; /* cps so far */ + l=(long)(zm.current_file_size/cps); /* total transfer est time */ + l-=t; /* now, it's est time left */ if(l<0) l=0; - fprintf(statfp,"\rKByte: %lu/%lu %u/CRC-%u " + fprintf(statfp,"\rKByte: %"PRId64"/%"PRId64" %u/CRC-%u " "Time: %lu:%02lu/%lu:%02lu %u cps %lu%% " ,current_pos/1024 ,zm.current_file_size/1024 @@ -764,7 +881,7 @@ void zmodem_progress(void* cbdata, ulong ,l/60L ,l%60L ,cps - ,(long)(((float)current_pos/(float)zm.current_file_size)*100.0) + ,zm.current_file_size?(long)(((float)current_pos/(float)zm.current_file_size)*100.0):100 ); newline=FALSE; last_progress=now; @@ -773,20 +890,20 @@ void zmodem_progress(void* cbdata, ulong static int send_files(char** fname, uint fnames) { - char path[MAX_PATH+1]; - int i; - uint errors; - uint fnum; - uint cps; - glob_t g; - int gi; - BOOL success=TRUE; - long fsize; - ulong sent_bytes; - ulong total_bytes=0; - time_t t,startfile; - time_t startall; - FILE* fp; + char path[MAX_PATH+1]; + int i; + uint errors; + uint fnum; + uint cps; + glob_t g; + int gi; + BOOL success=TRUE; + uint64_t fsize; + uint64_t sent_bytes; + uint64_t total_bytes=0; + time_t t,startfile; + time_t startall; + FILE* fp; startall=time(NULL); @@ -812,7 +929,7 @@ static int send_files(char** fname, uint return(-1); } if(xm.total_files>1) - lprintf(LOG_INFO,"Sending %u files (%lu KB total)" + lprintf(LOG_INFO,"Sending %u files (%"PRId64" KB total)" ,xm.total_files,xm.total_bytes/1024); zm.files_remaining = xm.total_files; @@ -841,47 +958,49 @@ static int send_files(char** fname, uint fsize=filelength(fileno(fp)); errors=0; - success=FALSE; startfile=time(NULL); - lprintf(LOG_INFO,"Sending %s (%lu KB) via %s" + lprintf(LOG_INFO,"Sending %s (%"PRId64" KB) via %cMODEM" ,path,fsize/1024 - ,mode&XMODEM ? "Xmodem" : mode&YMODEM ? "Ymodem" : "Zmodem"); + ,mode&XMODEM ? 'X' : mode&YMODEM ? 'Y' : 'Z'); 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 */ - success=xmodem_send_file(&xm, path, fp, &startfile, &sent_bytes); + success=xmodem_send_file(&xm, path, fp, &startfile, &sent_bytes); fclose(fp); if((t=time(NULL)-startfile)<=0) t=1; - if((cps=sent_bytes/t)==0) + if((cps=(unsigned)(sent_bytes/t))==0) cps=1; if(success) { xm.sent_files++; xm.sent_bytes+=fsize; - lprintf(LOG_INFO,"Successful - Time: %lu:%02lu CPS: %lu" + if(zm.file_skipped) + lprintf(LOG_WARNING,"File Skipped"); + else + lprintf(LOG_INFO,"Successful - Time: %lu:%02lu CPS: %lu" ,t/60,t%60,cps); if(xm.total_files-xm.sent_files) - lprintf(LOG_INFO,"Remaining - Time: %lu:%02lu Files: %u KBytes: %lu" + lprintf(LOG_INFO,"Remaining - Time: %lu:%02lu Files: %u KBytes: %"PRId64 ,((xm.total_bytes-xm.sent_bytes)/cps)/60 ,((xm.total_bytes-xm.sent_bytes)/cps)%60 ,xm.total_files-xm.sent_files ,(xm.total_bytes-xm.sent_bytes)/1024 ); } else - lprintf(LOG_WARNING,"File Transfer %s", aborted ? "Aborted" : "Failure"); + lprintf(LOG_WARNING,"File Transfer %s", zm.local_abort ? "Aborted" : "Failure"); /* DSZLOG entry */ if(logfp) { lprintf(LOG_DEBUG,"Updating DSZLOG: %s", dszlog); - fprintf(logfp,"%c %7lu %5u bps %6lu cps %3u errors %5u %4u " + fprintf(logfp,"%c %7"PRId64" %5u bps %6lu cps %3u errors %5u %4u " "%s -1\n" - ,success ? (mode&ZMODEM ? 'z':'S') - : (mode&ZMODEM && zm.file_skipped) ? 's' + ,(mode&ZMODEM && zm.file_skipped) ? 's' + : success ? (mode&ZMODEM ? 'z':'S') : 'E' ,sent_bytes ,115200 /* baud */ @@ -894,13 +1013,13 @@ static int send_files(char** fname, uint } total_bytes += sent_bytes; - if(aborted) { + if(zm.local_abort) { xm.cancelled=FALSE; xmodem_cancel(&xm); break; } - if(xm.cancelled || zm.cancelled) + if(xm.cancelled || zm.cancelled || !success) break; } /* while(gi<(int)g.gl_pathc) */ @@ -909,7 +1028,7 @@ static int send_files(char** fname, uint break; } - if(mode&ZMODEM && !zm.cancelled && is_connected(NULL)) + if(mode&ZMODEM && !zm.cancelled && is_connected(NULL) && (success || total_bytes)) zmodem_get_zfin(&zm); if(fnum1) { t=time(NULL)-startall; if(!t) t=1; - lprintf(LOG_INFO,"Overall - Time %02lu:%02lu KBytes: %lu CPS: %lu" + lprintf(LOG_INFO,"Overall - Time %02lu:%02lu KBytes: %"PRId64" CPS: %lu" ,t/60,t%60,total_bytes/1024,total_bytes/t); } return(0); /* success */ @@ -955,8 +1074,8 @@ static int receive_files(char** fname_li BOOL success=FALSE; long fmode; long serial_num=-1; - ulong file_bytes=0,file_bytes_left=0; - ulong total_bytes=0; + int64_t file_bytes=0,file_bytes_left=0; + int64_t total_bytes=0; FILE* fp; time_t t,startfile,ftime; @@ -970,34 +1089,37 @@ static int receive_files(char** fname_li lprintf(LOG_WARNING,"Throwing out received: %s",chr((uchar)i)); while(is_connected(NULL)) { + file_bytes=0x7fffffff; if(mode&XMODEM) { SAFECOPY(str,fname_list[0]); /* we'll have at least one fname */ - file_bytes=file_bytes_left=0x7fffffff; + file_bytes_left=file_bytes; } - else { if(mode&YMODEM) { - lprintf(LOG_INFO,"Fetching Ymodem header block"); + lprintf(LOG_INFO,"Fetching YMODEM header block"); for(errors=0;errors<=xm.max_errors && !xm.cancelled;errors++) { - if(errors>(xm.max_errors/2) && mode&CRC && !(mode&GMODE)) - mode&=~CRC; xmodem_put_nak(&xm, /* expected_block: */ 0); - if(xmodem_get_block(&xm, block, /* expected_block: */ 0) == 0) { + if(xmodem_get_block(&xm, block, /* expected_block: */ 0) == SUCCESS) { send_byte(NULL,ACK,10); break; } + if(errors+1>xm.max_errors/3 && mode&CRC && !(mode&GMODE)) { + lprintf(LOG_NOTICE,"Falling back to 8-bit Checksum mode"); + mode&=~CRC; + } } - if(errors>=xm.max_errors || xm.cancelled) { - lprintf(LOG_ERR,"Error fetching Ymodem header block"); + if(errors>xm.max_errors || xm.cancelled) { + lprintf(LOG_ERR,"Error fetching YMODEM header block"); xmodem_cancel(&xm); return(1); } if(!block[0]) { - lprintf(LOG_INFO,"Received Ymodem termination block"); + lprintf(LOG_INFO,"Received YMODEM termination block"); return(0); } - file_bytes=ftime=total_files=total_bytes=0; - i=sscanf(block+strlen(block)+1,"%ld %lo %lo %lo %d %ld" + ftime=total_files=0; + total_bytes=0; + i=sscanf(block+strlen(block)+1,"%"PRId64" %lo %lo %lo %u %"PRId64 ,&file_bytes /* file size (decimal) */ ,&ftime /* file time (octal unix format) */ ,&fmode /* file mode (not used) */ @@ -1005,11 +1127,11 @@ static int receive_files(char** fname_li ,&total_files /* remaining files to be sent */ ,&total_bytes /* remaining bytes to be sent */ ); - lprintf(LOG_DEBUG,"Ymodem header (%u fields): %s", i, block+strlen(block)+1); + lprintf(LOG_DEBUG,"YMODEM header (%u fields): %s", i, block+strlen(block)+1); SAFECOPY(fname,block); } else { /* Zmodem */ - lprintf(LOG_INFO,"Waiting for Zmodem sender..."); + lprintf(LOG_INFO,"Waiting for ZMODEM sender..."); i=zmodem_recv_init(&zm); @@ -1032,9 +1154,6 @@ static int receive_files(char** fname_li return(-1); } } - - if(!file_bytes) - file_bytes=0x7fffffff; file_bytes_left=file_bytes; if(!total_files) total_files=fnames-fnum; @@ -1069,9 +1188,9 @@ static int receive_files(char** fname_li } } } - fprintf(statfp,"File size: %lu bytes\n", file_bytes); + fprintf(statfp,"File size: %"PRId64" bytes\n", file_bytes); if(total_files>1) - fprintf(statfp,"Remaining: %lu bytes in %u files\n", total_bytes, total_files); + fprintf(statfp,"Remaining: %"PRId64" bytes in %u files\n", total_bytes, total_files); } lprintf(LOG_DEBUG,"Receiving: %.64s ",str); @@ -1093,6 +1212,17 @@ static int receive_files(char** fname_li xmodem_cancel(&xm); return(1); } + + if(!(mode&XMODEM) && max_file_size!=0 && file_bytes > max_file_size) { + lprintf(LOG_WARNING,"%s file size (%"PRId64") exceeds specified maximum: %"PRId64" bytes", str, file_bytes, max_file_size); + if(mode&ZMODEM) { + zmodem_send_zskip(&zm); + continue; + } + xmodem_cancel(&xm); + return(1); + } + if((fp=fnopen(NULL,str,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY))==NULL && (fp=fopen(str,"wb"))==NULL) { lprintf(LOG_ERR,"Error %d creating %s",errno,str); @@ -1105,14 +1235,15 @@ static int receive_files(char** fname_li } if(mode&XMODEM) - lprintf(LOG_INFO,"Receiving %s via Xmodem %s" + lprintf(LOG_INFO,"Receiving %s via XMODEM%s %s" ,str + ,mode&GMODE ? "-G" : "" ,mode&CRC ? "CRC-16":"Checksum"); else - lprintf(LOG_INFO,"Receiving %s (%lu KB) via %s %s" + lprintf(LOG_INFO,"Receiving %s (%"PRId64" KB) via %s %s" ,str ,file_bytes/1024 - ,mode&YMODEM ? mode&GMODE ? "Ymodem-G" : "Ymodem" :"Zmodem" + ,mode&YMODEM ? mode&GMODE ? "YMODEM-G" : "YMODEM" :"ZMODEM" ,mode&ZMODEM ? "" : (mode&CRC ? "CRC-16" : "Checksum")); startfile=time(NULL); @@ -1121,24 +1252,24 @@ static int receive_files(char** fname_li errors=zmodem_recv_file_data(&zm,fp,0); - /* - * wait for the eof header - */ - - for(;errors<=zm.max_errors && !success && !zm.cancelled; errors++) { - if(zmodem_recv_header_and_check(&zm)) - success=TRUE; - } + if(errors<=zm.max_errors && !zm.cancelled) + success=TRUE; } else { errors=0; block_num=1; xmodem_put_nak(&xm, block_num); while(is_connected(NULL)) { - xmodem_progress(NULL,block_num,ftell(fp),file_bytes,startfile); + off_t pos=ftello(fp); + if(max_file_size!=0 && pos>=max_file_size) { + lprintf(LOG_WARNING,"Specified maximum file size (%"PRId64" bytes) reached at offset %"PRId64 + ,max_file_size, pos); + break; + } + xmodem_progress(NULL,block_num,pos,file_bytes,startfile); i=xmodem_get_block(&xm, block, block_num); - if(i!=0) { + if(i!=SUCCESS) { if(i==EOT) { /* end of transfer */ success=TRUE; xmodem_put_ack(&xm); @@ -1149,31 +1280,31 @@ static int receive_files(char** fname_li break; } - if(mode&GMODE) - return(-1); - - if(++errors>=xm.max_errors) { + if(++errors>xm.max_errors || (mode&GMODE)) { lprintf(LOG_ERR,"Too many errors (%u)",errors); xmodem_cancel(&xm); break; } - if(block_num==1 && errors>(xm.max_errors/2) && mode&CRC && !(mode&GMODE)) + if(i!=NOT_XMODEM + && block_num==1 && errors>xm.max_errors/3 && mode&CRC && !(mode&GMODE)) { + lprintf(LOG_NOTICE,"Falling back to 8-bit Checksum mode (error=%d)", i); mode&=~CRC; + } xmodem_put_nak(&xm, block_num); continue; } if(!(mode&GMODE)) send_byte(NULL,ACK,10); - if(file_bytes_left<=0L) { /* No more bytes to send */ - lprintf(LOG_WARNING,"Attempt to send more byte specified in header"); + if(file_bytes_left<=0L) { /* No more bytes to receive */ + lprintf(LOG_WARNING,"Sender attempted to send more bytes than were specified in header"); break; } wr=xm.block_size; - if(wr>file_bytes_left) - wr=file_bytes_left; + if(wr>(uint)file_bytes_left) + wr=(uint)file_bytes_left; if(fwrite(block,1,wr,fp)!=wr) { - lprintf(LOG_ERR,"Error writing %u bytes to file at offset %lu" - ,wr,ftell(fp)); + lprintf(LOG_ERR,"ERROR %d writing %u bytes at file offset %"PRIu64 + ,errno, wr, (uint64_t)ftello(fp)); xmodem_cancel(&xm); return(1); } @@ -1183,21 +1314,28 @@ static int receive_files(char** fname_li } /* Use correct file size */ - fflush(fp); - if(file_bytes < (ulong)filelength(fileno(fp))) { - lprintf(LOG_INFO,"Truncating file to %lu bytes", file_bytes); - chsize(fileno(fp),file_bytes); - } else - file_bytes = filelength(fileno(fp)); + if(mode&ZMODEM) + file_bytes = zm.current_file_size; /* file can grow in transit */ + else { + fflush(fp); + if(file_bytes < filelength(fileno(fp))) { + lprintf(LOG_INFO,"Truncating file to %"PRIu64" bytes", file_bytes); + chsize(fileno(fp),(ulong)file_bytes); /* <--- 4GB limit */ + } else + file_bytes = filelength(fileno(fp)); + } fclose(fp); - + t=time(NULL)-startfile; if(!t) t=1; - if(success) + if(zm.file_skipped) + lprintf(LOG_WARNING,"File Skipped"); + else if(success) lprintf(LOG_INFO,"Successful - Time: %lu:%02lu CPS: %lu" - ,t/60,t%60,file_bytes/t); + ,t/60,t%60,(ulong)(file_bytes/t)); else - lprintf(LOG_ERR,"File Transfer %s", aborted ? "Aborted":"Failure"); + lprintf(LOG_ERR,"File Transfer %s" + ,zm.local_abort ? "Aborted": zm.cancelled ? "Cancelled":"Failure"); if(!(mode&XMODEM) && ftime) setfdate(str,ftime); @@ -1218,10 +1356,10 @@ static int receive_files(char** fname_li fflush(logfp); } - if(aborted) { + if(zm.local_abort) { lprintf(LOG_DEBUG,"Locally aborted, sending cancel to remote"); if(mode&ZMODEM) - zmodem_abort_receive(&zm); + zmodem_send_zabort(&zm); xm.cancelled=FALSE; xmodem_cancel(&xm); break; @@ -1229,12 +1367,12 @@ static int receive_files(char** fname_li if(mode&XMODEM) /* maximum of one file */ break; - if((cps=file_bytes/t)==0) + if((cps=(unsigned)(file_bytes/t))==0) cps=1; total_files--; total_bytes-=file_bytes; if(total_files>1 && total_bytes) - lprintf(LOG_INFO,"Remaining - Time: %lu:%02lu Files: %u KBytes: %lu" + lprintf(LOG_INFO,"Remaining - Time: %lu:%02lu Files: %u KBytes: %"PRIu64 ,(total_bytes/cps)/60 ,(total_bytes/cps)%60 ,total_files @@ -1264,27 +1402,85 @@ static const char* usage= "socket = TCP socket descriptor\n" #endif "\n" - "opts = -y to overwrite files when receiving\n" + "opts = -y allow overwriting of existing files when receiving\n" " -o disable Zmodem CRC-32 mode (use CRC-16)\n" " -s disable Zmodem streaming (Slow Zmodem)\n" + " -k enable X/Ymodem-1K send mode\n" + " -c enable Xmodem-CRC receive mode\n" + " -g enable X/Ymodem-G receive mode (no error recovery)\n" " -2 set maximum Zmodem block size to 2K\n" " -4 set maximum Zmodem block size to 4K\n" " -8 set maximum Zmodem block size to 8K (ZedZap)\n" + " -m# set maximum receive file size to # bytes (0=unlimited, default=%u)\n" " -! to pause after abnormal exit (error)\n" +#ifdef __unix__ + " -telnet to enable Telnet mode (the default except in stdio mode)\n" +#else " -telnet to enable Telnet mode (the default)\n" +#endif " -rlogin or -ssh or -raw to disable Telnet mode\n" "\n" "cmd = v to display detailed version information\n" - " sx to send Xmodem rx to recv Xmodem\n" - " sX to send Xmodem-1K rc to recv Xmodem-CRC\n" - " sy to send Ymodem ry to recv Ymodem\n" - " sY to send Ymodem-1K rg to recv Ymodem-G\n" - " sz to send Zmodem rz to recv Zmodem\n" + " sx to send Xmodem rx to receive Xmodem\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-1K rg to receive Ymodem-G\n" + " sz to send Zmodem rz to receive Zmodem\n" "\n" "file = filename to send or receive\n" "path = directory to receive files into\n" "list = name of text file with list of filenames to send or receive\n"; +#ifdef __unix__ + +struct termios tio_default; /* Initial term settings */ + +#ifdef NEEDS_CFMAKERAW +static void +cfmakeraw(struct termios *t) +{ + t->c_iflag &= ~(IMAXBEL|IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); + t->c_oflag &= ~OPOST; + t->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); + t->c_cflag &= ~(CSIZE|PARENB); + t->c_cflag |= CS8; +} +#endif + +static void fixterm(void) +{ + tcsetattr(STDIN_FILENO,TCSANOW,&tio_default); +} + +static void init_stdio(void) +{ + struct termios tio_raw; + + if(isatty(STDERR_FILENO)) + fclose(stderr); + + if (isatty(STDIN_FILENO)) { + tcgetattr(STDIN_FILENO,&tio_default); + tio_raw = tio_default; + /* cfmakeraw(&tio_raw); */ + tio_raw.c_iflag &= ~(IMAXBEL|IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); + tio_raw.c_oflag &= ~OPOST; + tio_raw.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); + tio_raw.c_cflag &= ~(CSIZE|PARENB); + tio_raw.c_cflag |= CS8; + tcsetattr(STDIN_FILENO,TCSANOW,&tio_raw); + setvbuf(stdout, NULL, _IOFBF, 0); + atexit(fixterm); + } +} + +BOOL RingBufIsEmpty(void *buf) +{ + return(RingBufFull(buf)==0); +} + +#endif + /***************/ /* Entry Point */ /***************/ @@ -1301,6 +1497,7 @@ int main(int argc, char **argv) FILE* fp; BOOL tcp_nodelay; char compiler[32]; + BOOL telnet_requested=FALSE; str_list_t fname_list; fname_list=strListInit(); @@ -1314,17 +1511,19 @@ int main(int argc, char **argv) statfp=stdout; #endif - sscanf("$Revision: 1.1 $", "%*s %s", revision); + sscanf("$Revision: 1.1.1.2 $", "%*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" ,revision ,PLATFORM_DESC ,__DATE__+7 ); - xmodem_init(&xm,NULL,&mode,lputs,xmodem_progress,send_byte,recv_byte,is_connected,NULL); - zmodem_init(&zm,NULL,lputs,zmodem_progress,send_byte,recv_byte,is_connected,NULL,data_waiting); + xmodem_init(&xm,NULL,&mode,lputs,xmodem_progress,send_byte,recv_byte,is_connected,NULL,flush); + zmodem_init(&zm,NULL,lputs,zmodem_progress,send_byte,recv_byte,is_connected,NULL,data_waiting,flush); + xm.log_level=&log_level; + zm.log_level=&log_level; /* Generate path/sexyz[.host].ini from path/sexyz[.exe] */ SAFECOPY(str,argv[0]); @@ -1350,12 +1549,14 @@ int main(int argc, char **argv) pause_on_abend =iniReadBool(fp,ROOT_SECTION,"PauseOnAbend",FALSE); log_level =iniReadLogLevel(fp,ROOT_SECTION,"LogLevel",log_level); + use_syslog =iniReadBool(fp,ROOT_SECTION,"SysLog",use_syslog); - outbuf.highwater_mark =iniReadInteger(fp,ROOT_SECTION,"OutbufHighwaterMark",1100); + outbuf.highwater_mark =(ulong)iniReadBytes(fp,ROOT_SECTION,"OutbufHighwaterMark",1,1100); outbuf_drain_timeout =iniReadInteger(fp,ROOT_SECTION,"OutbufDrainTimeout",10); - outbuf_size =iniReadInteger(fp,ROOT_SECTION,"OutbufSize",16*1024); + outbuf_size =(ulong)iniReadBytes(fp,ROOT_SECTION,"OutbufSize",1,16*1024); progress_interval =iniReadInteger(fp,ROOT_SECTION,"ProgressInterval",1); + max_file_size =iniReadBytes(fp,ROOT_SECTION,"MaxFileSize",/* unit: */1,MAX_FILE_SIZE); if(iniReadBool(fp,ROOT_SECTION,"Debug",FALSE)) log_level=LOG_DEBUG; @@ -1364,18 +1565,23 @@ int main(int argc, char **argv) xm.recv_timeout =iniReadInteger(fp,"Xmodem","RecvTimeout",xm.recv_timeout); /* seconds */ xm.byte_timeout =iniReadInteger(fp,"Xmodem","ByteTimeout",xm.byte_timeout); /* seconds */ xm.ack_timeout =iniReadInteger(fp,"Xmodem","AckTimeout",xm.ack_timeout); /* seconds */ - xm.block_size =iniReadInteger(fp,"Xmodem","BlockSize",xm.block_size); /* 128 or 1024 */ + xm.block_size =(ulong)iniReadBytes(fp,"Xmodem","BlockSize",1,xm.block_size); /* 128 or 1024 */ + xm.max_block_size =(ulong)iniReadBytes(fp,"Xmodem","MaxBlockSize",1,xm.max_block_size); /* 128 or 1024 */ xm.max_errors =iniReadInteger(fp,"Xmodem","MaxErrors",xm.max_errors); xm.g_delay =iniReadInteger(fp,"Xmodem","G_Delay",xm.g_delay); + xm.crc_mode_supported =iniReadBool(fp,"Xmodem","SendCRC",xm.crc_mode_supported); + xm.g_mode_supported =iniReadBool(fp,"Xmodem","SendG",xm.g_mode_supported); + + xm.fallback_to_xmodem =iniReadInteger(fp,"Ymodem","FallbackToXmodem", xm.fallback_to_xmodem); zm.init_timeout =iniReadInteger(fp,"Zmodem","InitTimeout",zm.init_timeout); /* seconds */ zm.send_timeout =iniReadInteger(fp,"Zmodem","SendTimeout",zm.send_timeout); /* seconds */ zm.recv_timeout =iniReadInteger(fp,"Zmodem","RecvTimeout",zm.recv_timeout); /* seconds */ zm.crc_timeout =iniReadInteger(fp,"Zmodem","CrcTimeout",zm.crc_timeout); /* seconds */ - zm.block_size =iniReadInteger(fp,"Zmodem","BlockSize",zm.block_size); /* 1024 */ - zm.max_block_size =iniReadInteger(fp,"Zmodem","MaxBlockSize",zm.max_block_size); /* 1024 or 8192 */ + zm.block_size =(ulong)iniReadBytes(fp,"Zmodem","BlockSize",1,zm.block_size); /* 1024 */ + zm.max_block_size =(ulong)iniReadBytes(fp,"Zmodem","MaxBlockSize",1,zm.max_block_size); /* 1024 or 8192 */ zm.max_errors =iniReadInteger(fp,"Zmodem","MaxErrors",zm.max_errors); - zm.recv_bufsize =iniReadInteger(fp,"Zmodem","RecvBufSize",0); + zm.recv_bufsize =(ulong)iniReadBytes(fp,"Zmodem","RecvBufSize",1,0); zm.no_streaming =!iniReadBool(fp,"Zmodem","Streaming",TRUE); zm.want_fcs_16 =!iniReadBool(fp,"Zmodem","CRC32",TRUE); zm.escape_telnet_iac =iniReadBool(fp,"Zmodem","EscapeTelnetIAC",TRUE); @@ -1402,6 +1608,10 @@ int main(int argc, char **argv) #if !defined(RINGBUF_EVENT) outbuf_empty=CreateEvent(NULL,/* ManualReset */TRUE, /*InitialState */TRUE,NULL); +#ifdef __unix__ + outbuf_empty->cbdata=&outbuf; + outbuf_empty->verify=RingBufIsEmpty; +#endif #endif #if 0 @@ -1434,17 +1644,20 @@ int main(int argc, char **argv) mode|=XMODEM|CRC; break; case 'x': - xm.block_size=128; + xm.block_size=XMODEM_MIN_BLOCK_SIZE; case 'X': mode|=XMODEM; break; case 'b': /* sz/rz compatible */ case 'B': case 'y': - xm.block_size=128; + xm.block_size=XMODEM_MIN_BLOCK_SIZE; case 'Y': mode|=(YMODEM|CRC); break; + case 'k': /* Ymodem-Checksum for debug/test purposes only */ + mode|=YMODEM; + break; case 'g': case 'G': mode|=(YMODEM|CRC|GMODE); @@ -1455,8 +1668,9 @@ int main(int argc, char **argv) break; default: fprintf(statfp,"Unrecognized command '%s'\n\n",argv[i]); - fprintf(statfp,usage); + fprintf(statfp,usage,MAX_FILE_SIZE); bail(1); + return -1; } continue; } @@ -1472,6 +1686,7 @@ int main(int argc, char **argv) fprintf(statfp,"Compiled %s %.5s with %s\n",__DATE__,__TIME__,compiler); fprintf(statfp,"%s\n",os_version(str)); bail(0); + return 0; } arg=argv[i]; @@ -1479,10 +1694,12 @@ int main(int argc, char **argv) while(*arg=='-') arg++; if(stricmp(arg,"telnet")==0) { + telnet_requested=TRUE; telnet=TRUE; continue; } if(stricmp(arg,"rlogin")==0 || stricmp(arg,"ssh")==0 || stricmp(arg,"raw")==0) { + telnet_requested=FALSE; telnet=FALSE; continue; } @@ -1490,13 +1707,17 @@ int main(int argc, char **argv) log_level=LOG_DEBUG; continue; } + if(stricmp(arg,"syslog")==0) { + use_syslog=TRUE; + continue; + } if(stricmp(arg,"quotes")==0) { dszlog_quotes=TRUE; continue; } switch(toupper(*arg)) { case 'K': /* sz/rz compatible */ - xm.block_size=1024; + xm.block_size=XMODEM_MAX_BLOCK_SIZE; break; case 'C': /* sz/rz compatible */ mode|=CRC; @@ -1516,8 +1737,8 @@ int main(int argc, char **argv) case 'S': /* disable Zmodem streaming */ zm.no_streaming=TRUE; break; - case 'G': /* Ymodem-G */ - mode|=GMODE; + case 'G': /* Ymodem-G or Xmodem-G (a.k.a. Qmodem-G) */ + mode|=(GMODE|CRC); break; case 'Y': mode|=OVERWRITE; @@ -1525,6 +1746,9 @@ int main(int argc, char **argv) case '!': pause_on_abend=TRUE; break; + case 'M': /* MaxFileSize */ + max_file_size=strtoul(arg++,NULL,0); /* TODO: use strtoull() ? */ + break; } } } @@ -1533,11 +1757,13 @@ int main(int argc, char **argv) if(mode&RECVDIR) { fprintf(statfp,"!Cannot specify both directory and filename\n"); bail(1); + return -1; } sprintf(str,"%s",argv[i]+1); if((fp=fopen(str,"r"))==NULL) { fprintf(statfp,"!Error %d opening filelist: %s\n",errno,str); bail(1); + return -1; } while(!feof(fp) && !ferror(fp)) { if(!fgets(str,sizeof(str),fp)) @@ -1553,14 +1779,17 @@ int main(int argc, char **argv) if(mode&RECVDIR) { fprintf(statfp,"!Only one directory can be specified\n"); bail(1); + return -1; } if(fnames) { fprintf(statfp,"!Cannot specify both directory and filename\n"); bail(1); + return -1; } if(mode&SEND) { fprintf(statfp,"!Cannot send directory '%s'\n",argv[i]); bail(1); + return -1; } mode|=RECVDIR; } @@ -1568,8 +1797,22 @@ int main(int argc, char **argv) } } - if(!telnet) - zm.escape_telnet_iac = FALSE; + if(max_file_size) + fprintf(statfp,"Maximum receive file size: %"PRIi64"\n", max_file_size); + + if(!(mode&(SEND|RECV))) { + fprintf(statfp,"!No command specified\n\n"); + fprintf(statfp,usage,MAX_FILE_SIZE); + bail(1); + return -1; + } + + if(mode&(SEND|XMODEM) && !fnames) { /* Sending with any or recv w/Xmodem */ + fprintf(statfp,"!Must specify filename or filelist\n\n"); + fprintf(statfp,usage,MAX_FILE_SIZE); + bail(1); + return -1; + } if(sock==INVALID_SOCKET || sock<1) { #ifdef __unix__ @@ -1578,13 +1821,16 @@ int main(int argc, char **argv) else sock=STDIN_FILENO; stdio=TRUE; - + fprintf(statfp,"No socket descriptor specified, using STDIO\n"); - telnet=FALSE; + if(!telnet_requested) + telnet=FALSE; + init_stdio(); #else fprintf(statfp,"!No socket descriptor specified\n\n"); - fprintf(errfp,usage); + fprintf(errfp,usage,MAX_FILE_SIZE); bail(1); + return -1; #endif } #ifdef __unix__ @@ -1592,34 +1838,10 @@ int main(int argc, char **argv) statfp=stdout; #endif - if(!(mode&(SEND|RECV))) { - fprintf(statfp,"!No command specified\n\n"); - fprintf(statfp,usage); - bail(1); - } + if(!telnet) + zm.escape_telnet_iac = FALSE; - if(mode&(SEND|XMODEM) && !fnames) { /* Sending with any or recv w/Xmodem */ - fprintf(statfp,"!Must specify filename or filelist\n\n"); - fprintf(statfp,usage); - bail(1); - } - -#ifdef __unix__ - if(stdio) { - struct termios term; - memset(&term,0,sizeof(term)); - cfsetispeed(&term,B19200); - cfsetospeed(&term,B19200); - term.c_iflag &= ~(IMAXBEL|IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); - term.c_oflag &= ~OPOST; - term.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); - term.c_cflag &= ~(CSIZE|PARENB); - term.c_cflag |= CS8; - atexit(resetterm); - tcgetattr(STDOUT_FILENO, &origterm); - tcsetattr(STDOUT_FILENO, TCSADRAIN, &term); - } -#endif + zm.max_file_size = max_file_size; /* Code disabled. Why? ToDo */ /* if(mode&RECVDIR) @@ -1638,15 +1860,29 @@ int main(int argc, char **argv) } #endif + /* Set non-blocking mode */ +#ifdef __unix__ + if(stdio) { + fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK); + } + else +#endif + { + i=1; + ioctlsocket(sock, FIONBIO, &i); + } + if(!socket_check(sock, NULL, NULL, 0)) { lprintf(LOG_WARNING,"No socket connection"); bail(-1); + return -1; } if((dszlog=getenv("DSZLOG"))!=NULL) { if((logfp=fopen(dszlog,"w"))==NULL) { lprintf(LOG_WARNING,"Error %d opening DSZLOG file: %s",errno,dszlog); bail(-1); + return -1; } } @@ -1675,8 +1911,13 @@ int main(int argc, char **argv) #if !SINGLE_THREADED lprintf(LOG_DEBUG,"Waiting for output buffer to empty... "); - if(WaitForEvent(outbuf_empty,5000)!=WAIT_OBJECT_0) - lprintf(LOG_DEBUG,"FAILURE"); + if(RingBufFull(&outbuf)) { +#if !defined(RINGBUF_EVENT) + ResetEvent(outbuf_empty); +#endif + if(WaitForEvent(outbuf_empty,5000)!=WAIT_OBJECT_0) + lprintf(LOG_DEBUG,"FAILURE"); + } #endif terminate=TRUE; /* stop output thread */ @@ -1689,5 +1930,6 @@ int main(int argc, char **argv) fprintf(statfp,"\n"); bail(retval); + return retval; }