|
|
1.1 root 1: /* sexyz.c */
2:
3: /* Synchronet External X/Y/ZMODEM Transfer Protocols */
4:
1.1.1.2 ! root 5: /* $Id: sexyz.c,v 1.132 2011/07/14 08:30:52 rswindell Exp $ */
1.1 root 6:
7: /****************************************************************************
8: * @format.tab-size 4 (Plain Text/Source Code File Header) *
9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
10: * *
1.1.1.2 ! root 11: * Copyright 2011 Rob Swindell - http://www.synchro.net/copyright.html *
1.1 root 12: * *
13: * This program is free software; you can redistribute it and/or *
14: * modify it under the terms of the GNU General Public License *
15: * as published by the Free Software Foundation; either version 2 *
16: * of the License, or (at your option) any later version. *
17: * See the GNU General Public License for more details: gpl.txt or *
18: * http://www.fsf.org/copyleft/gpl.html *
19: * *
20: * Anonymous FTP access to the most recent released source is available at *
21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
22: * *
23: * Anonymous CVS access to the development source and modification history *
24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: *
25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login *
26: * (just hit return, no password is necessary) *
27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src *
28: * *
29: * For Synchronet coding style and modification guidelines, see *
30: * http://www.synchro.net/source.html *
31: * *
32: * You are encouraged to submit any modifications (preferably in Unix diff *
33: * format) via e-mail to [email protected] *
34: * *
35: * Note: If this box doesn't appear square, then you need to fix your tabs. *
36: ****************************************************************************/
37:
38: /*
39: * ZMODEM code based on zmtx/zmrx v1.02 (C) Mattheij Computer Service 1994
40: * by Jacques Mattheij <[email protected]>
41: */
42:
43: #include <time.h>
44: #include <stdio.h>
45: #include <errno.h>
46: #include <string.h>
47: #include <stdlib.h>
48: #include <stdarg.h>
49: #include <ctype.h> /* isdigit */
50: #include <sys/stat.h>
51:
52: #ifdef __unix__
53: #include <termios.h>
54: #include <signal.h>
55: #endif
56:
57: /* xpdev */
58: #include "conwrap.h"
59: #include "genwrap.h"
60: #include "semwrap.h"
61: #include "dirwrap.h"
62: #include "filewrap.h"
63: #include "sockwrap.h"
64: #include "str_list.h"
65: #include "ini_file.h"
66: #include "eventwrap.h"
67: #include "threadwrap.h"
68:
69: /* sbbs */
70: #include "ringbuf.h"
71: #include "telnet.h"
72: #include "nopen.h"
73:
74: /* sexyz */
75: #include "sexyz.h"
76:
77: #define SINGLE_THREADED FALSE
78: #define MIN_OUTBUF_SIZE 1024
79: #define MAX_OUTBUF_SIZE (64*1024)
1.1.1.2 ! root 80: #define INBUF_SIZE (64*1024)
! 81: #define MAX_FILE_SIZE 0 /* Default value for max recv file size, 0 = unlimited*/
1.1 root 82:
83: /***************/
84: /* Global Vars */
85: /***************/
86: long mode=0; /* Program mode */
87: long zmode=0L; /* Zmodem mode */
1.1.1.2 ! root 88: uchar block[XMODEM_MAX_BLOCK_SIZE]; /* Block buffer */
1.1 root 89: ulong block_num; /* Block number */
90: char* dszlog;
91: BOOL dszlog_path=TRUE; /* Log complete path to filename */
92: BOOL dszlog_short=FALSE; /* Log Micros~1 short filename */
93: BOOL dszlog_quotes=FALSE; /* Quote filenames in DSZLOG */
94: int log_level=LOG_INFO;
1.1.1.2 ! root 95: BOOL use_syslog=FALSE;
! 96: int64_t max_file_size=MAX_FILE_SIZE;
1.1 root 97:
98: xmodem_t xm;
99: zmodem_t zm;
100:
101: FILE* errfp;
102: FILE* statfp;
103: FILE* logfp=NULL;
104:
105: char revision[16];
106:
107: SOCKET sock=INVALID_SOCKET;
108:
109: BOOL telnet=TRUE;
110: #ifdef __unix__
111: BOOL stdio=FALSE;
112: #endif
113: BOOL terminate=FALSE;
114: BOOL debug_tx=FALSE;
115: BOOL debug_rx=FALSE;
116: BOOL debug_telnet=FALSE;
117: BOOL pause_on_exit=FALSE;
118: BOOL pause_on_abend=FALSE;
119: BOOL newline=TRUE;
1.1.1.2 ! root 120: BOOL connected=TRUE;
1.1 root 121:
122: time_t progress_interval;
123:
124: RingBuf outbuf;
125: #if defined(RINGBUF_EVENT)
126: #define outbuf_empty outbuf.empty_event
127: #else
128: xpevent_t outbuf_empty;
129: #endif
130: unsigned outbuf_drain_timeout;
131: long outbuf_size;
132:
1.1.1.2 ! root 133: uchar inbuf[INBUF_SIZE];
! 134: unsigned inbuf_pos=0;
! 135: unsigned inbuf_len=0;
! 136:
1.1 root 137: unsigned flows=0;
138: unsigned select_errors=0;
139:
140: #ifdef _WINSOCKAPI_
141:
142: /* Note: Don't call WSACleanup() or TCP session will close! */
143: WSADATA WSAData;
144:
145: static BOOL winsock_startup(void)
146: {
147: int status; /* Status Code */
148:
149: if((status = WSAStartup(MAKEWORD(1,1), &WSAData))==0) {
150: fprintf(statfp,"%s %s\n",WSAData.szDescription, WSAData.szSystemStatus);
151: return(TRUE);
152: }
153:
154: fprintf(errfp,"!WinSock startup ERROR %d\n", status);
155: return(FALSE);
156: }
157:
158: #else /* No WINSOCK */
159:
160: #define winsock_startup() (TRUE)
161:
162: #endif
163:
164: static int lputs(void* unused, int level, const char* str)
165: {
166: FILE* fp=statfp;
1.1.1.2 ! root 167: int ret;
1.1 root 168:
169: #if defined(_WIN32) && defined(_DEBUG)
170: if(log_level==LOG_DEBUG)
171: OutputDebugString(str);
172: #endif
173:
174: if(level>log_level)
175: return 0;
176:
177: if(level<LOG_NOTICE)
178: fp=errfp;
179:
180: if(!newline) {
181: fprintf(fp,"\n");
182: newline=TRUE;
183: }
184: if(level<LOG_NOTICE)
1.1.1.2 ! root 185: ret=fprintf(fp,"!%s\n",str);
1.1 root 186: else
1.1.1.2 ! root 187: ret=fprintf(fp,"%s\n",str);
! 188:
! 189: #if defined(__unix__)
! 190: if(use_syslog) {
! 191: char* msg;
! 192: char* p;
! 193: if((msg=strdup(str))!=NULL) {
! 194: REPLACE_CHARS(msg,'\r',' ',p);
! 195: REPLACE_CHARS(msg,'\n',' ',p);
! 196: syslog(level,"%s",msg);
! 197: free(msg);
! 198: }
! 199: }
! 200: #endif
! 201:
! 202: return ret;
1.1 root 203: }
204:
205: static int lprintf(int level, const char *fmt, ...)
206: {
207: char sbuf[1024];
208: va_list argptr;
209:
1.1.1.2 ! root 210: if(level>log_level)
! 211: return 0;
! 212:
1.1 root 213: va_start(argptr,fmt);
214: vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
215: sbuf[sizeof(sbuf)-1]=0;
216: va_end(argptr);
217: return(lputs(NULL,level,sbuf));
218: }
219:
220: void break_handler(int type)
221: {
222: lprintf(LOG_NOTICE,"-> Aborted Locally (signal: %d)",type);
223:
224: /* Flag to indicate local (as opposed to remote) abort */
1.1.1.2 ! root 225: zm.local_abort=TRUE;
1.1 root 226:
227: /* Stop any transfers in progress immediately */
228: xm.cancelled=TRUE;
229: zm.cancelled=TRUE;
230: }
231:
232: #if defined(_WIN32)
1.1.1.2 ! root 233: BOOL WINAPI ControlHandler(unsigned long CtrlType)
1.1 root 234: {
235: break_handler((int)CtrlType);
236: return TRUE;
237: }
238: #endif
239:
240: char* dszlog_filename(char* str)
241: {
242: char* p=str;
243: static char path[MAX_PATH+1];
244:
245: #ifdef _WIN32
246: char sfpath[MAX_PATH+1];
247: if(dszlog_short) {
248: SAFECOPY(sfpath,str);
249: GetShortPathName(str,sfpath,sizeof(sfpath));
250: p=sfpath;
251: }
252: #endif
253:
254: if(!dszlog_path)
255: p=getfname(p);
256:
257: if(!dszlog_quotes)
258: return(p);
259:
260: SAFEPRINTF(path,"\"%s\"",p);
261: return(path);
262: }
263:
264: static char *chr(uchar ch)
265: {
266: static char str[25];
267:
268: if(mode&ZMODEM) {
269: switch(ch) {
270: case ZRQINIT: return("ZRQINIT");
271: case ZRINIT: return("ZRINIT");
272: case ZSINIT: return("ZSINIT");
273: case ZACK: return("ZACK");
274: case ZFILE: return("ZFILE");
275: case ZSKIP: return("ZSKIP");
276: case ZNAK: return("ZNAK");
277: case ZABORT: return("ZABORT");
278: case ZFIN: return("ZFIN");
279: case ZRPOS: return("ZRPOS");
280: case ZDATA: return("ZDATA");
281: case ZEOF: return("ZEOF");
282: case ZPAD: return("ZPAD");
283: case ZDLE: return("ZDLE");
284: case ZDLEE: return("ZDLEE");
285: case ZBIN: return("ZBIN");
286: case ZHEX: return("ZHEX");
287: case ZBIN32: return("ZBIN32");
288: case ZRESC: return("ZRESC");
289: case ZCRCE: return("ZCRCE");
290: case ZCRCG: return("ZCRCG");
291: case ZCRCQ: return("ZCRCQ");
292: case ZCRCW: return("ZCRCW");
293: }
294: } else {
295: switch(ch) {
296: case SOH: return("SOH");
297: case STX: return("STX");
298: case ETX: return("ETX");
299: case EOT: return("EOT");
300: case ACK: return("ACK");
301: case NAK: return("NAK");
302: case CAN: return("CAN");
303: }
304: }
305: if(ch>=' ' && ch<='~')
306: sprintf(str,"'%c' (%02Xh)",ch,ch);
307: else
308: sprintf(str,"%u (%02Xh)",ch,ch);
309: return(str);
310: }
311:
312: void dump(BYTE* buf, int len)
313: {
314: char str[128];
315: int i,j;
316: size_t slen=0;
317:
318: slen=sprintf(str,"TX: ");
319: for(i=0;i<len;i+=j) {
320: for(j=0;i+j<len && j<32;j++)
321: slen+=sprintf(str+slen,"%02X ",buf[i+j]);
322: lprintf(LOG_DEBUG,"%s",str);
323: slen=sprintf(str,"TX: ");
324: }
325: }
326:
1.1.1.2 ! root 327: int sendbuf(SOCKET s, void *buf, size_t buflen)
! 328: {
! 329: size_t sent=0;
! 330: int ret;
! 331: fd_set socket_set;
! 332:
! 333: for(;;) {
! 334: #ifdef __unix__
! 335: if(stdio)
! 336: ret=write(STDOUT_FILENO, (char *)buf+sent,buflen-sent);
! 337: else
! 338: #endif
! 339: ret=sendsocket(s,(char *)buf+sent,buflen-sent);
! 340: if(ret==SOCKET_ERROR) {
! 341: switch(ERROR_VALUE) {
! 342: case EAGAIN:
! 343: case ENOBUFS:
! 344: #if (EAGAIN != EWOULDBLOCK)
! 345: case EWOULDBLOCK:
! 346: #endif
! 347: /* Block until we can send */
! 348: FD_ZERO(&socket_set);
! 349: #ifdef __unix__
! 350: if(stdio)
! 351: FD_SET(STDIN_FILENO,&socket_set);
! 352: else
! 353: #endif
! 354: FD_SET(sock,&socket_set);
! 355:
! 356: if((ret=select(sock+1,NULL,&socket_set,NULL,NULL))<1) {
! 357: if(ret==SOCKET_ERROR && ERROR_VALUE != EINTR) {
! 358: lprintf(LOG_ERR,"ERROR %d selecting socket", ERROR_VALUE);
! 359: goto disconnect;
! 360: }
! 361: }
! 362: break;
! 363: default:
! 364: goto disconnect;
! 365: }
! 366: }
! 367: else {
! 368: sent += ret;
! 369: if(sent >= buflen)
! 370: return(sent);
! 371: }
! 372: }
! 373:
! 374: disconnect:
! 375: lprintf(LOG_DEBUG,"DISCONNECTED line %u", __LINE__);
! 376: connected=FALSE;
! 377: if(sent)
! 378: return sent;
! 379: return SOCKET_ERROR;
! 380: }
! 381:
1.1 root 382: void send_telnet_cmd(SOCKET sock, uchar cmd, uchar opt)
383: {
384: uchar buf[3];
385:
386: buf[0]=TELNET_IAC;
387: buf[1]=cmd;
388: buf[2]=opt;
389:
390: if(debug_telnet)
391: lprintf(LOG_DEBUG,"Sending telnet command: %s %s"
392: ,telnet_cmd_desc(buf[1]),telnet_opt_desc(buf[2]));
393:
1.1.1.2 ! root 394: if(sendbuf(sock,buf,sizeof(buf))!=sizeof(buf) && debug_telnet)
1.1 root 395: lprintf(LOG_ERR,"FAILED");
396: }
397:
398: #define DEBUG_TELNET FALSE
399:
1.1.1.2 ! root 400: /*
! 401: * Returns -1 on disconnect or the number of bytes read.
! 402: * Does not muck around with ERROR_VALUE (hopefully)
! 403: */
! 404: static int recv_buffer(int timeout /* seconds */)
! 405: {
! 406: int i;
! 407: fd_set socket_set;
! 408: struct timeval tv;
! 409: int magic_errno;
! 410:
! 411: for(;;) {
! 412: if(inbuf_len > inbuf_pos)
! 413: return(inbuf_len-inbuf_pos);
! 414: #ifdef __unix__
! 415: if(stdio) {
! 416: i=read(STDIN_FILENO,inbuf,sizeof(inbuf));
! 417: /* Look like a socket using MAGIC! */
! 418: switch(i) {
! 419: case 0:
! 420: i=-1;
! 421: magic_errno=EAGAIN;
! 422: break;
! 423: case -1:
! 424: magic_errno=errno;
! 425: break;
! 426: }
! 427: }
! 428: else
! 429: #endif
! 430: {
! 431: i=recv(sock,inbuf,sizeof(inbuf),0);
! 432: if(i==SOCKET_ERROR)
! 433: magic_errno=ERROR_VALUE;
! 434: }
! 435: if(i==SOCKET_ERROR) {
! 436: switch(magic_errno) {
! 437: case EAGAIN:
! 438: case EINTR:
! 439: #if (EAGAIN != EWOULDBLOCK)
! 440: case EWOULDBLOCK:
! 441: #endif
! 442: // Call select()
! 443: if(timeout) {
! 444: FD_ZERO(&socket_set);
! 445: #ifdef __unix__
! 446: if(stdio)
! 447: FD_SET(STDIN_FILENO,&socket_set);
! 448: else
! 449: #endif
! 450: FD_SET(sock,&socket_set);
! 451: tv.tv_sec=timeout;
! 452: timeout=0;
! 453: tv.tv_usec=0;
! 454: if((i=select(sock+1,&socket_set,NULL,NULL,&tv))<1) {
! 455: if(i==SOCKET_ERROR) {
! 456: lprintf(LOG_ERR,"ERROR %d selecting socket", magic_errno);
! 457: connected=FALSE;
! 458: }
! 459: else
! 460: lprintf(LOG_WARNING,"Receive timeout (%u seconds)", timeout);
! 461: }
! 462: else
! 463: continue;
! 464: }
! 465: return 0;
! 466: default:
! 467: lprintf(LOG_DEBUG,"DISCONNECTED line %u, error=%u", __LINE__,magic_errno);
! 468: connected=FALSE;
! 469: return -1;
! 470: }
! 471: return -1; // Impossible.
! 472: }
! 473: else if(i==0) {
! 474: lprintf(LOG_DEBUG,"DISCONNECTED line %u", __LINE__);
! 475: connected=FALSE;
! 476: return -1;
! 477: }
! 478: else {
! 479: inbuf_len=i;
! 480: return i;
! 481: }
! 482: };
! 483: }
! 484:
1.1 root 485: /****************************************************************************/
486: /* Receive a byte from remote (single-threaded version) */
487: /****************************************************************************/
1.1.1.2 ! root 488: int recv_byte(void* unused, unsigned timeout /* seconds */)
1.1 root 489: {
490: int i;
491: uchar ch;
492: static uchar telnet_cmd;
493: static int telnet_cmdlen;
494:
1.1.1.2 ! root 495: while((inbuf_len || connected) && !terminate) {
! 496: if(inbuf_len) {
! 497: ch=inbuf[inbuf_pos++];
! 498: i=1;
! 499: if(inbuf_pos >= inbuf_len)
! 500: inbuf_pos=inbuf_len=0;
! 501: }
! 502: else {
! 503: i=recv_buffer(timeout);
! 504: switch(i) {
! 505: case -1:
! 506: i=0;
! 507: break;
! 508: case 0:
! 509: return NOINP;
! 510: default:
! 511: i=1;
! 512: continue;
! 513: }
1.1 root 514: }
515:
516: if(i!=sizeof(ch)) {
517: if(i==0) {
518: lprintf(LOG_WARNING,"Socket Disconnected");
519: } else
520: lprintf(LOG_ERR,"recv error %d (%d)",i,ERROR_VALUE);
521: return(NOINP);
522: }
523:
524: if(telnet) {
525: if(ch==TELNET_IAC) {
526: #if DEBUG_TELNET
527: lprintf(LOG_DEBUG,"T<%s> ",telnet_cmd_desc(ch));
528: #endif
529: if(telnet_cmdlen==0) {
530: telnet_cmdlen=1;
531: continue;
532: }
533: if(telnet_cmdlen==1) {
534: telnet_cmdlen=0;
535: if(debug_rx)
536: lprintf(LOG_DEBUG,"RX: %s",chr(TELNET_IAC));
537: return(TELNET_IAC);
538: }
539: }
540: if(telnet_cmdlen) {
541: telnet_cmdlen++;
542: #if DEBUG_TELNET
543: if(telnet_cmdlen==2)
544: lprintf(LOG_DEBUG,"T<%s> ",telnet_cmd_desc(ch));
545: else
546: lprintf(LOG_DEBUG,"T<%s> ",telnet_opt_desc(ch));
547: #endif
548: if(debug_telnet && telnet_cmdlen==3)
549: lprintf(LOG_DEBUG,"Received telnet command: %s %s"
550: ,telnet_cmd_desc(telnet_cmd),telnet_opt_desc(ch));
551: if(telnet_cmdlen==3 && telnet_cmd==TELNET_DO)
552: send_telnet_cmd(sock, TELNET_WILL,ch);
553: /*
554: else if(telnet_cmdlen==3 && telnet_cmd==TELNET_WILL)
555: send_telnet_cmd(sock, TELNET_DO,ch);
556: */
557: telnet_cmd=ch;
558: if((telnet_cmdlen==2 && ch<TELNET_WILL) || telnet_cmdlen>2) {
559: telnet_cmdlen=0;
560: /* Code disabled. Why? ToDo */
561: /* break; */
562: }
563: continue;
564: }
565: }
566: if(debug_rx)
567: lprintf(LOG_DEBUG,"RX: %s",chr(ch));
568: return(ch);
569: }
570:
571: return(NOINP);
572: }
573:
574: #if !SINGLE_THREADED
575: /*************************/
576: /* Send a byte to remote */
577: /*************************/
578: int send_byte(void* unused, uchar ch, unsigned timeout)
579: {
580: uchar buf[2] = { TELNET_IAC, TELNET_IAC };
581: unsigned len=1;
582: DWORD result;
583:
584: if(telnet && ch==TELNET_IAC) /* escape IAC char */
585: len=2;
586: else
587: buf[0]=ch;
588:
589: if(RingBufFree(&outbuf)<len) {
1.1.1.2 ! root 590: #if !defined(RINGBUF_EVENT)
! 591: ResetEvent(outbuf_empty);
! 592: #endif
1.1 root 593: fprintf(statfp,"FLOW");
594: flows++;
595: result=WaitForEvent(outbuf_empty,timeout*1000);
596: fprintf(statfp,"\b\b\b\b \b\b\b\b");
597: if(result!=WAIT_OBJECT_0) {
1.1.1.2 ! root 598: lprintf(LOG_WARNING
! 599: ,"!TIMEOUT (%d) waiting for output buffer to flush (%u seconds, %u bytes)\n"
! 600: ,result, timeout, RingBufFull(&outbuf));
1.1 root 601: fprintf(statfp
602: ,"\n!TIMEOUT (%d) waiting for output buffer to flush (%u seconds, %u bytes)\n"
603: ,result, timeout, RingBufFull(&outbuf));
604: newline=TRUE;
1.1.1.2 ! root 605: if((result=RingBufFree(&outbuf))<len) {
! 606: lprintf(LOG_ERR,"Still not enough space in ring buffer (need %d, avail=%d)",len,result);
1.1 root 607: return(-1);
1.1.1.2 ! root 608: }
! 609: }
! 610: if((result=RingBufFree(&outbuf))<len) {
! 611: lprintf(LOG_ERR,"Not enough space in ring buffer (need %d, avail=%d) although empty event is set!",len,result);
! 612: return(-1);
1.1 root 613: }
614: }
615:
1.1.1.2 ! root 616: if((result=RingBufWrite(&outbuf,buf,len))!=len) {
! 617: lprintf(LOG_ERR,"RingBufWrite() returned %d, expected %d",result,len);
! 618: }
1.1 root 619:
620: #if 0
621: if(debug_tx)
622: lprintf(LOG_DEBUG,"TX: %s",chr(ch));
623: #endif
624: return(0);
625: }
626:
627: #else
628:
629: /*************************/
630: /* Send a byte to remote */
631: /*************************/
632: int send_byte(void* unused, uchar ch, unsigned timeout)
633: {
634: uchar buf[2] = { TELNET_IAC, TELNET_IAC };
635: int len=1;
636: int i;
637:
638: if(telnet && ch==TELNET_IAC) /* escape IAC char */
639: len=2;
640: else
641: buf[0]=ch;
642:
1.1.1.2 ! root 643: i=sendbuf(sock,buf,len);
1.1 root 644:
645: if(i==len) {
646: if(debug_tx)
647: lprintf(LOG_DEBUG,"TX: %s",chr(ch));
648: return(0);
649: }
650:
651: return(-1);
652: }
653: #endif
654:
655: static void output_thread(void* arg)
656: {
657: char stats[128];
658: BYTE buf[MAX_OUTBUF_SIZE];
659: int i;
660: ulong avail;
1.1.1.2 ! root 661: uint64_t total_sent=0;
! 662: uint64_t total_pkts=0;
1.1 root 663: ulong short_sends=0;
664: ulong bufbot=0;
665: ulong buftop=0;
666:
667: #if 0 /* def _DEBUG */
668: fprintf(statfp,"output thread started\n");
669: #endif
670:
671: while(sock!=INVALID_SOCKET && !terminate) {
672:
673: if(bufbot==buftop)
674: avail=RingBufFull(&outbuf);
675: else
676: avail=buftop-bufbot;
677:
678: if(!avail) {
679: #if !defined(RINGBUF_EVENT)
680: SetEvent(outbuf_empty);
681: #endif
682: sem_wait(&outbuf.sem);
683: if(outbuf.highwater_mark)
684: sem_trywait_block(&outbuf.highwater_sem,outbuf_drain_timeout);
685: continue;
686: }
687:
688: if(bufbot==buftop) { /* linear buf empty, read from ring buf */
689: if(avail>sizeof(buf)) {
690: lprintf(LOG_ERR,"Insufficient linear output buffer (%lu > %lu)"
691: ,avail, sizeof(buf));
692: avail=sizeof(buf);
693: }
694: buftop=RingBufRead(&outbuf, buf, avail);
695: bufbot=0;
696: }
1.1.1.2 ! root 697: i=sendbuf(sock, (char*)buf+bufbot, buftop-bufbot);
1.1 root 698: if(i==SOCKET_ERROR) {
699: if(ERROR_VALUE == ENOTSOCK)
700: lprintf(LOG_ERR,"client socket closed on send");
701: else if(ERROR_VALUE==ECONNRESET)
702: lprintf(LOG_ERR,"connection reset by peer on send");
703: else if(ERROR_VALUE==ECONNABORTED)
704: lprintf(LOG_ERR,"connection aborted by peer on send");
705: else
706: lprintf(LOG_ERR,"ERROR %d sending on socket %d"
707: ,ERROR_VALUE, sock);
708: break;
709: }
710:
711: if(debug_tx)
712: dump(buf+bufbot,i);
713:
714: if(i!=(int)(buftop-bufbot)) {
715: lprintf(LOG_ERR,"Short socket send (%u instead of %u)"
716: ,i ,buftop-bufbot);
717: short_sends++;
718: }
719: bufbot+=i;
720: total_sent+=i;
721: total_pkts++;
722: }
723:
724: if(total_sent)
1.1.1.2 ! root 725: sprintf(stats,"(sent %"PRIu64" bytes in %"PRIu64" blocks, %"PRIu64" average, %lu short, %lu errors)"
1.1 root 726: ,total_sent, total_pkts, total_sent/total_pkts, short_sends, select_errors);
727: else
728: stats[0]=0;
729:
730: lprintf(LOG_DEBUG,"output thread terminated\n%s", stats);
731: }
732:
1.1.1.2 ! root 733: /* Flush output buffer */
! 734: void flush(void* unused)
1.1 root 735: {
1.1.1.2 ! root 736: #ifdef __unix__
! 737: if(stdio)
! 738: fflush(stdout);
! 739: #endif
1.1 root 740: }
741:
1.1.1.2 ! root 742: BOOL is_connected(void* unused)
1.1 root 743: {
1.1.1.2 ! root 744: if(inbuf_len > inbuf_pos)
! 745: return TRUE;
! 746: return connected;
! 747: }
1.1 root 748:
1.1.1.2 ! root 749: BOOL data_waiting(void* unused, unsigned timeout /* seconds */)
! 750: {
! 751: if(recv_buffer(timeout) > 0)
! 752: return TRUE;
! 753: return FALSE;
1.1 root 754: }
755:
756: /****************************************************************************/
1.1.1.2 ! root 757: /* Returns the total number of blocks required to send the file */
1.1 root 758: /****************************************************************************/
1.1.1.2 ! root 759: uint64_t num_blocks(unsigned block_num, uint64_t offset, uint64_t len, unsigned block_size)
1.1 root 760: {
1.1.1.2 ! root 761: uint64_t blocks;
! 762: uint64_t remain = len - offset;
1.1 root 763:
1.1.1.2 ! root 764: blocks=block_num + (remain/block_size);
! 765: if(remain%block_size)
1.1 root 766: blocks++;
767: return(blocks);
768: }
769:
770: /************************************************/
771: /* Dump the current block contents - for debug */
772: /************************************************/
773: void dump_block(long block_size)
774: {
775: long l;
776:
777: for(l=0;l<block_size;l++)
778: fprintf(statfp,"%02X ",block[l]);
779: fprintf(statfp,"\n");
780: }
781:
1.1.1.2 ! root 782: void xmodem_progress(void* unused, unsigned block_num, int64_t offset, int64_t fsize, time_t start)
1.1 root 783: {
784: unsigned cps;
1.1.1.2 ! root 785: uint64_t total_blocks;
1.1 root 786: long l;
787: long t;
788: time_t now;
789: static time_t last_progress;
790:
791: now=time(NULL);
792: if(now-last_progress>=progress_interval || offset >= fsize || newline) {
793: t=now-start;
794: if(t<=0)
795: t=1;
1.1.1.2 ! root 796: if((cps=(unsigned)(offset/t))==0)
! 797: cps=1; /* cps so far */
! 798: l=(long)(fsize/cps); /* total transfer est time */
! 799: l-=t; /* now, it's est time left */
1.1 root 800: if(l<0) l=0;
801: if(mode&SEND) {
1.1.1.2 ! root 802: total_blocks=num_blocks(block_num,offset,fsize,xm.block_size);
! 803: fprintf(statfp,"\rBlock (%lu%s): %lu/%"PRId64" Byte: %"PRId64" "
1.1 root 804: "Time: %lu:%02lu/%lu:%02lu %u cps %lu%% "
805: ,xm.block_size%1024L ? xm.block_size: xm.block_size/1024L
806: ,xm.block_size%1024L ? "" : "K"
807: ,block_num
808: ,total_blocks
809: ,offset
810: ,t/60L
811: ,t%60L
812: ,l/60L
813: ,l%60L
814: ,cps
1.1.1.2 ! root 815: ,fsize?(long)(((float)offset/(float)fsize)*100.0):100
1.1 root 816: );
817: } else if(mode&YMODEM) {
1.1.1.2 ! root 818: fprintf(statfp,"\rBlock (%lu%s): %lu Byte: %"PRId64" "
1.1 root 819: "Time: %lu:%02lu/%lu:%02lu %u cps %lu%% "
820: ,xm.block_size%1024L ? xm.block_size: xm.block_size/1024L
821: ,xm.block_size%1024L ? "" : "K"
822: ,block_num
823: ,offset
824: ,t/60L
825: ,t%60L
826: ,l/60L
827: ,l%60L
828: ,cps
1.1.1.2 ! root 829: ,fsize?(long)(((float)offset/(float)fsize)*100.0):100
1.1 root 830: );
831: } else { /* XModem receive */
1.1.1.2 ! root 832: fprintf(statfp,"\rBlock (%lu%s): %lu Byte: %"PRId64" "
1.1 root 833: "Time: %lu:%02lu %u cps "
834: ,xm.block_size%1024L ? xm.block_size: xm.block_size/1024L
835: ,xm.block_size%1024L ? "" : "K"
836: ,block_num
837: ,offset
838: ,t/60L
839: ,t%60L
840: ,cps
841: );
842: }
843: newline=FALSE;
844: last_progress=now;
845: }
846: }
847:
848: /*
849: * show the progress of the transfer like this:
850: * zmtx: sending file "garbage" 4096 bytes ( 20%)
851: */
1.1.1.2 ! root 852: void zmodem_progress(void* cbdata, int64_t current_pos)
1.1 root 853: {
854: unsigned cps;
855: long l;
856: long t;
857: time_t now;
858: static time_t last_progress;
859:
860: now=time(NULL);
861: if(now-last_progress>=progress_interval || current_pos >= zm.current_file_size || newline) {
862: t=now-zm.transfer_start_time;
863: if(t<=0)
864: t=1;
865: if(zm.transfer_start_pos>current_pos)
866: zm.transfer_start_pos=0;
1.1.1.2 ! root 867: if((cps=(unsigned)((current_pos-zm.transfer_start_pos)/t))==0)
! 868: cps=1; /* cps so far */
! 869: l=(long)(zm.current_file_size/cps); /* total transfer est time */
! 870: l-=t; /* now, it's est time left */
1.1 root 871: if(l<0) l=0;
1.1.1.2 ! root 872: fprintf(statfp,"\rKByte: %"PRId64"/%"PRId64" %u/CRC-%u "
1.1 root 873: "Time: %lu:%02lu/%lu:%02lu %u cps %lu%% "
874: ,current_pos/1024
875: ,zm.current_file_size/1024
876: ,zm.block_size
877: ,mode&RECV ? (zm.receive_32bit_data ? 32:16) :
878: (zm.can_fcs_32 && !zm.want_fcs_16) ? 32:16
879: ,t/60L
880: ,t%60L
881: ,l/60L
882: ,l%60L
883: ,cps
1.1.1.2 ! root 884: ,zm.current_file_size?(long)(((float)current_pos/(float)zm.current_file_size)*100.0):100
1.1 root 885: );
886: newline=FALSE;
887: last_progress=now;
888: }
889: }
890:
891: static int send_files(char** fname, uint fnames)
892: {
1.1.1.2 ! root 893: char path[MAX_PATH+1];
! 894: int i;
! 895: uint errors;
! 896: uint fnum;
! 897: uint cps;
! 898: glob_t g;
! 899: int gi;
! 900: BOOL success=TRUE;
! 901: uint64_t fsize;
! 902: uint64_t sent_bytes;
! 903: uint64_t total_bytes=0;
! 904: time_t t,startfile;
! 905: time_t startall;
! 906: FILE* fp;
1.1 root 907:
908: startall=time(NULL);
909:
910: /****************************************************/
911: /* Search through all to find total files and bytes */
912: /****************************************************/
913: for(fnum=0;fnum<fnames;fnum++) {
914: if(glob(fname[fnum],0,NULL,&g)) {
915: lprintf(LOG_WARNING,"%s not found",fname[fnum]);
916: continue;
917: }
918: for(i=0;i<(int)g.gl_pathc;i++) {
919: if(isdir(g.gl_pathv[i]))
920: continue;
921: xm.total_files++;
922: xm.total_bytes+=flength(g.gl_pathv[i]);
923: }
924: globfree(&g);
925: }
926:
927: if(xm.total_files<1) {
928: lprintf(LOG_ERR,"No files to send");
929: return(-1);
930: }
931: if(xm.total_files>1)
1.1.1.2 ! root 932: lprintf(LOG_INFO,"Sending %u files (%"PRId64" KB total)"
1.1 root 933: ,xm.total_files,xm.total_bytes/1024);
934:
935: zm.files_remaining = xm.total_files;
936: zm.bytes_remaining = xm.total_bytes;
937:
938: /***********************************************/
939: /* Send every file matching names or filespecs */
940: /***********************************************/
941: for(fnum=0;fnum<fnames;fnum++) {
942: if(glob(fname[fnum],0,NULL,&g)) {
943: lprintf(LOG_WARNING,"%s not found",fname[fnum]);
944: continue;
945: }
946: for(gi=0;gi<(int)g.gl_pathc;gi++) {
947: SAFECOPY(path,g.gl_pathv[gi]);
948: if(isdir(path))
949: continue;
950:
951: if((fp=fnopen(NULL,path,O_RDONLY|O_BINARY))==NULL
952: && (fp=fopen(path,"rb"))==NULL) {
953: lprintf(LOG_ERR,"Error %d opening %s for read",errno,path);
954: continue;
955: }
956: setvbuf(fp,NULL,_IOFBF,0x10000);
957:
958: fsize=filelength(fileno(fp));
959:
960: errors=0;
961: startfile=time(NULL);
962:
1.1.1.2 ! root 963: lprintf(LOG_INFO,"Sending %s (%"PRId64" KB) via %cMODEM"
1.1 root 964: ,path,fsize/1024
1.1.1.2 ! root 965: ,mode&XMODEM ? 'X' : mode&YMODEM ? 'Y' : 'Z');
1.1 root 966:
967: if(mode&ZMODEM)
1.1.1.2 ! root 968: success=zmodem_send_file(&zm, path, fp, /* ZRQINIT? */fnum==0, &startfile, &sent_bytes);
1.1 root 969: else /* X/Ymodem */
1.1.1.2 ! root 970: success=xmodem_send_file(&xm, path, fp, &startfile, &sent_bytes);
1.1 root 971:
972: fclose(fp);
973:
974: if((t=time(NULL)-startfile)<=0)
975: t=1;
1.1.1.2 ! root 976: if((cps=(unsigned)(sent_bytes/t))==0)
1.1 root 977: cps=1;
978: if(success) {
979: xm.sent_files++;
980: xm.sent_bytes+=fsize;
1.1.1.2 ! root 981: if(zm.file_skipped)
! 982: lprintf(LOG_WARNING,"File Skipped");
! 983: else
! 984: lprintf(LOG_INFO,"Successful - Time: %lu:%02lu CPS: %lu"
1.1 root 985: ,t/60,t%60,cps);
986:
987: if(xm.total_files-xm.sent_files)
1.1.1.2 ! root 988: lprintf(LOG_INFO,"Remaining - Time: %lu:%02lu Files: %u KBytes: %"PRId64
1.1 root 989: ,((xm.total_bytes-xm.sent_bytes)/cps)/60
990: ,((xm.total_bytes-xm.sent_bytes)/cps)%60
991: ,xm.total_files-xm.sent_files
992: ,(xm.total_bytes-xm.sent_bytes)/1024
993: );
994: } else
1.1.1.2 ! root 995: lprintf(LOG_WARNING,"File Transfer %s", zm.local_abort ? "Aborted" : "Failure");
1.1 root 996:
997: /* DSZLOG entry */
998: if(logfp) {
999: lprintf(LOG_DEBUG,"Updating DSZLOG: %s", dszlog);
1.1.1.2 ! root 1000: fprintf(logfp,"%c %7"PRId64" %5u bps %6lu cps %3u errors %5u %4u "
1.1 root 1001: "%s -1\n"
1.1.1.2 ! root 1002: ,(mode&ZMODEM && zm.file_skipped) ? 's'
! 1003: : success ? (mode&ZMODEM ? 'z':'S')
1.1 root 1004: : 'E'
1005: ,sent_bytes
1006: ,115200 /* baud */
1007: ,cps
1008: ,mode&ZMODEM ? zm.errors : xm.errors
1009: ,flows
1010: ,mode&ZMODEM ? zm.block_size : xm.block_size
1011: ,dszlog_filename(path));
1012: fflush(logfp);
1013: }
1014: total_bytes += sent_bytes;
1015:
1.1.1.2 ! root 1016: if(zm.local_abort) {
1.1 root 1017: xm.cancelled=FALSE;
1018: xmodem_cancel(&xm);
1019: break;
1020: }
1021:
1.1.1.2 ! root 1022: if(xm.cancelled || zm.cancelled || !success)
1.1 root 1023: break;
1024:
1025: } /* while(gi<(int)g.gl_pathc) */
1026:
1027: if(gi<(int)g.gl_pathc)/* error occurred */
1028: break;
1029: }
1030:
1.1.1.2 ! root 1031: if(mode&ZMODEM && !zm.cancelled && is_connected(NULL) && (success || total_bytes))
1.1 root 1032: zmodem_get_zfin(&zm);
1033:
1034: if(fnum<fnames) /* error occurred */
1035: return(-1);
1036:
1037: if(!success)
1038: return(-1);
1039:
1040: if(mode&XMODEM)
1041: return(0);
1042: if(mode&YMODEM) {
1043:
1044: if(xmodem_get_mode(&xm)) {
1045:
1.1.1.2 ! root 1046: lprintf(LOG_INFO,"Sending YMODEM termination block");
1.1 root 1047:
1.1.1.2 ! root 1048: memset(block,0,XMODEM_MIN_BLOCK_SIZE); /* send short block for terminator */
! 1049: xmodem_put_block(&xm, block, XMODEM_MIN_BLOCK_SIZE /* block_size */, 0 /* block_num */);
! 1050: if(xmodem_get_ack(&xm, /* tries: */6, /* block_num: */0) != ACK) {
1.1 root 1051: lprintf(LOG_WARNING,"Failed to receive ACK after terminating block");
1052: }
1053: }
1054: }
1055: if(xm.total_files>1) {
1056: t=time(NULL)-startall;
1057: if(!t) t=1;
1.1.1.2 ! root 1058: lprintf(LOG_INFO,"Overall - Time %02lu:%02lu KBytes: %"PRId64" CPS: %lu"
1.1 root 1059: ,t/60,t%60,total_bytes/1024,total_bytes/t);
1060: }
1061: return(0); /* success */
1062: }
1063:
1064: static int receive_files(char** fname_list, int fnames)
1065: {
1066: char str[MAX_PATH+1];
1067: char fname[MAX_PATH+1];
1068: int i;
1069: int fnum=0;
1070: uint errors;
1071: uint total_files=0;
1072: uint cps;
1073: uint wr;
1074: BOOL success=FALSE;
1075: long fmode;
1076: long serial_num=-1;
1.1.1.2 ! root 1077: int64_t file_bytes=0,file_bytes_left=0;
! 1078: int64_t total_bytes=0;
1.1 root 1079: FILE* fp;
1080: time_t t,startfile,ftime;
1081:
1082: if(fnames>1)
1083: lprintf(LOG_INFO,"Receiving %u files",fnames);
1084:
1085: outbuf.highwater_mark=0; /* don't delay ACK/NAK transmits */
1086:
1087: /* Purge input buffer */
1088: while(is_connected(NULL) && (i=recv_byte(NULL,0))!=NOINP)
1089: lprintf(LOG_WARNING,"Throwing out received: %s",chr((uchar)i));
1090:
1091: while(is_connected(NULL)) {
1.1.1.2 ! root 1092: file_bytes=0x7fffffff;
1.1 root 1093: if(mode&XMODEM) {
1094: SAFECOPY(str,fname_list[0]); /* we'll have at least one fname */
1.1.1.2 ! root 1095: file_bytes_left=file_bytes;
1.1 root 1096: }
1097: else {
1098: if(mode&YMODEM) {
1.1.1.2 ! root 1099: lprintf(LOG_INFO,"Fetching YMODEM header block");
1.1 root 1100: for(errors=0;errors<=xm.max_errors && !xm.cancelled;errors++) {
1101: xmodem_put_nak(&xm, /* expected_block: */ 0);
1.1.1.2 ! root 1102: if(xmodem_get_block(&xm, block, /* expected_block: */ 0) == SUCCESS) {
1.1 root 1103: send_byte(NULL,ACK,10);
1104: break;
1105: }
1.1.1.2 ! root 1106: if(errors+1>xm.max_errors/3 && mode&CRC && !(mode&GMODE)) {
! 1107: lprintf(LOG_NOTICE,"Falling back to 8-bit Checksum mode");
! 1108: mode&=~CRC;
! 1109: }
1.1 root 1110: }
1.1.1.2 ! root 1111: if(errors>xm.max_errors || xm.cancelled) {
! 1112: lprintf(LOG_ERR,"Error fetching YMODEM header block");
1.1 root 1113: xmodem_cancel(&xm);
1114: return(1);
1115: }
1116: if(!block[0]) {
1.1.1.2 ! root 1117: lprintf(LOG_INFO,"Received YMODEM termination block");
1.1 root 1118: return(0);
1119: }
1.1.1.2 ! root 1120: ftime=total_files=0;
! 1121: total_bytes=0;
! 1122: i=sscanf(block+strlen(block)+1,"%"PRId64" %lo %lo %lo %u %"PRId64
1.1 root 1123: ,&file_bytes /* file size (decimal) */
1124: ,&ftime /* file time (octal unix format) */
1125: ,&fmode /* file mode (not used) */
1126: ,&serial_num /* program serial number */
1127: ,&total_files /* remaining files to be sent */
1128: ,&total_bytes /* remaining bytes to be sent */
1129: );
1.1.1.2 ! root 1130: lprintf(LOG_DEBUG,"YMODEM header (%u fields): %s", i, block+strlen(block)+1);
1.1 root 1131: SAFECOPY(fname,block);
1132:
1133: } else { /* Zmodem */
1.1.1.2 ! root 1134: lprintf(LOG_INFO,"Waiting for ZMODEM sender...");
1.1 root 1135:
1136: i=zmodem_recv_init(&zm);
1137:
1138: if(zm.cancelled)
1139: return(1);
1140: if(i<0)
1141: return(-1);
1142: switch(i) {
1143: case ZFILE:
1144: SAFECOPY(fname,zm.current_file_name);
1145: file_bytes = zm.current_file_size;
1146: ftime = zm.current_file_time;
1147: total_files = zm.files_remaining;
1148: total_bytes = zm.bytes_remaining;
1149: break;
1150: case ZFIN:
1151: case ZCOMPL:
1152: return(!success);
1153: default:
1154: return(-1);
1155: }
1156: }
1157: file_bytes_left=file_bytes;
1158: if(!total_files)
1159: total_files=fnames-fnum;
1160: if(!total_files)
1161: total_files=1;
1162: if(total_bytes<file_bytes)
1163: total_bytes=file_bytes;
1164:
1165: lprintf(LOG_DEBUG,"Incoming filename: %.64s ",fname);
1166:
1167: if(mode&RECVDIR)
1168: sprintf(str,"%s%s",fname_list[0],getfname(fname));
1169: else {
1170: SAFECOPY(str,getfname(fname));
1171: for(i=0;i<fnames;i++) {
1172: if(!fname_list[i][0]) /* name blank or already used */
1173: continue;
1174: if(!stricmp(getfname(fname_list[i]),str)) {
1175: SAFECOPY(str,fname_list[i]);
1176: fname_list[i][0]=0;
1177: break;
1178: }
1179: }
1180: if(i==fnames) { /* Not found in list */
1181: if(fnames)
1182: fprintf(statfp," - Not in receive list!");
1183: if(!fnames || fnum>=fnames || !fname_list[fnum][0])
1184: SAFECOPY(str,getfname(fname)); /* worst case */
1185: else {
1186: SAFECOPY(str,fname_list[fnum]);
1187: fname_list[fnum][0]=0;
1188: }
1189: }
1190: }
1.1.1.2 ! root 1191: fprintf(statfp,"File size: %"PRId64" bytes\n", file_bytes);
1.1 root 1192: if(total_files>1)
1.1.1.2 ! root 1193: fprintf(statfp,"Remaining: %"PRId64" bytes in %u files\n", total_bytes, total_files);
1.1 root 1194: }
1195:
1196: lprintf(LOG_DEBUG,"Receiving: %.64s ",str);
1197:
1198: fnum++;
1199:
1200: if(!(mode&RECVDIR) && fnames && fnum>fnames) {
1201: lprintf(LOG_WARNING,"Attempt to send more files than specified");
1202: xmodem_cancel(&xm);
1203: break;
1204: }
1205:
1206: if(fexistcase(str) && !(mode&OVERWRITE)) {
1207: lprintf(LOG_WARNING,"%s already exists",str);
1208: if(mode&ZMODEM) {
1209: zmodem_send_zskip(&zm);
1210: continue;
1211: }
1212: xmodem_cancel(&xm);
1213: return(1);
1214: }
1.1.1.2 ! root 1215:
! 1216: if(!(mode&XMODEM) && max_file_size!=0 && file_bytes > max_file_size) {
! 1217: lprintf(LOG_WARNING,"%s file size (%"PRId64") exceeds specified maximum: %"PRId64" bytes", str, file_bytes, max_file_size);
! 1218: if(mode&ZMODEM) {
! 1219: zmodem_send_zskip(&zm);
! 1220: continue;
! 1221: }
! 1222: xmodem_cancel(&xm);
! 1223: return(1);
! 1224: }
! 1225:
1.1 root 1226: if((fp=fnopen(NULL,str,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY))==NULL
1227: && (fp=fopen(str,"wb"))==NULL) {
1228: lprintf(LOG_ERR,"Error %d creating %s",errno,str);
1229: if(mode&ZMODEM) {
1230: zmodem_send_zskip(&zm);
1231: continue;
1232: }
1233: xmodem_cancel(&xm);
1234: return(1);
1235: }
1236:
1237: if(mode&XMODEM)
1.1.1.2 ! root 1238: lprintf(LOG_INFO,"Receiving %s via XMODEM%s %s"
1.1 root 1239: ,str
1.1.1.2 ! root 1240: ,mode&GMODE ? "-G" : ""
1.1 root 1241: ,mode&CRC ? "CRC-16":"Checksum");
1242: else
1.1.1.2 ! root 1243: lprintf(LOG_INFO,"Receiving %s (%"PRId64" KB) via %s %s"
1.1 root 1244: ,str
1245: ,file_bytes/1024
1.1.1.2 ! root 1246: ,mode&YMODEM ? mode&GMODE ? "YMODEM-G" : "YMODEM" :"ZMODEM"
1.1 root 1247: ,mode&ZMODEM ? "" : (mode&CRC ? "CRC-16" : "Checksum"));
1248:
1249: startfile=time(NULL);
1250: success=FALSE;
1251: if(mode&ZMODEM) {
1252:
1253: errors=zmodem_recv_file_data(&zm,fp,0);
1254:
1.1.1.2 ! root 1255: if(errors<=zm.max_errors && !zm.cancelled)
! 1256: success=TRUE;
1.1 root 1257:
1258: } else {
1259: errors=0;
1260: block_num=1;
1261: xmodem_put_nak(&xm, block_num);
1262: while(is_connected(NULL)) {
1.1.1.2 ! root 1263: off_t pos=ftello(fp);
! 1264: if(max_file_size!=0 && pos>=max_file_size) {
! 1265: lprintf(LOG_WARNING,"Specified maximum file size (%"PRId64" bytes) reached at offset %"PRId64
! 1266: ,max_file_size, pos);
! 1267: break;
! 1268: }
! 1269: xmodem_progress(NULL,block_num,pos,file_bytes,startfile);
1.1 root 1270: i=xmodem_get_block(&xm, block, block_num);
1271:
1.1.1.2 ! root 1272: if(i!=SUCCESS) {
1.1 root 1273: if(i==EOT) { /* end of transfer */
1274: success=TRUE;
1275: xmodem_put_ack(&xm);
1276: break;
1277: }
1278: if(i==CAN) { /* Cancel */
1279: xm.cancelled=TRUE;
1280: break;
1281: }
1282:
1.1.1.2 ! root 1283: if(++errors>xm.max_errors || (mode&GMODE)) {
1.1 root 1284: lprintf(LOG_ERR,"Too many errors (%u)",errors);
1285: xmodem_cancel(&xm);
1286: break;
1287: }
1.1.1.2 ! root 1288: if(i!=NOT_XMODEM
! 1289: && block_num==1 && errors>xm.max_errors/3 && mode&CRC && !(mode&GMODE)) {
! 1290: lprintf(LOG_NOTICE,"Falling back to 8-bit Checksum mode (error=%d)", i);
1.1 root 1291: mode&=~CRC;
1.1.1.2 ! root 1292: }
1.1 root 1293: xmodem_put_nak(&xm, block_num);
1294: continue;
1295: }
1296: if(!(mode&GMODE))
1297: send_byte(NULL,ACK,10);
1.1.1.2 ! root 1298: if(file_bytes_left<=0L) { /* No more bytes to receive */
! 1299: lprintf(LOG_WARNING,"Sender attempted to send more bytes than were specified in header");
1.1 root 1300: break;
1301: }
1302: wr=xm.block_size;
1.1.1.2 ! root 1303: if(wr>(uint)file_bytes_left)
! 1304: wr=(uint)file_bytes_left;
1.1 root 1305: if(fwrite(block,1,wr,fp)!=wr) {
1.1.1.2 ! root 1306: lprintf(LOG_ERR,"ERROR %d writing %u bytes at file offset %"PRIu64
! 1307: ,errno, wr, (uint64_t)ftello(fp));
1.1 root 1308: xmodem_cancel(&xm);
1309: return(1);
1310: }
1311: file_bytes_left-=wr;
1312: block_num++;
1313: }
1314: }
1315:
1316: /* Use correct file size */
1.1.1.2 ! root 1317: if(mode&ZMODEM)
! 1318: file_bytes = zm.current_file_size; /* file can grow in transit */
! 1319: else {
! 1320: fflush(fp);
! 1321: if(file_bytes < filelength(fileno(fp))) {
! 1322: lprintf(LOG_INFO,"Truncating file to %"PRIu64" bytes", file_bytes);
! 1323: chsize(fileno(fp),(ulong)file_bytes); /* <--- 4GB limit */
! 1324: } else
! 1325: file_bytes = filelength(fileno(fp));
! 1326: }
1.1 root 1327: fclose(fp);
1.1.1.2 ! root 1328:
1.1 root 1329: t=time(NULL)-startfile;
1330: if(!t) t=1;
1.1.1.2 ! root 1331: if(zm.file_skipped)
! 1332: lprintf(LOG_WARNING,"File Skipped");
! 1333: else if(success)
1.1 root 1334: lprintf(LOG_INFO,"Successful - Time: %lu:%02lu CPS: %lu"
1.1.1.2 ! root 1335: ,t/60,t%60,(ulong)(file_bytes/t));
1.1 root 1336: else
1.1.1.2 ! root 1337: lprintf(LOG_ERR,"File Transfer %s"
! 1338: ,zm.local_abort ? "Aborted": zm.cancelled ? "Cancelled":"Failure");
1.1 root 1339:
1340: if(!(mode&XMODEM) && ftime)
1341: setfdate(str,ftime);
1342:
1343: if(logfp) {
1344: lprintf(LOG_DEBUG,"Updating DSZLOG: %s", dszlog);
1345: fprintf(logfp,"%c %6lu %5u bps %4lu cps %3u errors %5u %4u "
1346: "%s %d\n"
1347: ,success ? (mode&ZMODEM ? 'Z' : 'R') : 'E'
1348: ,file_bytes
1349: ,115200 /* baud */
1350: ,file_bytes/t
1351: ,errors
1352: ,flows
1353: ,mode&ZMODEM ? zm.block_size : xm.block_size
1354: ,dszlog_filename(str)
1355: ,serial_num);
1356: fflush(logfp);
1357: }
1358:
1.1.1.2 ! root 1359: if(zm.local_abort) {
1.1 root 1360: lprintf(LOG_DEBUG,"Locally aborted, sending cancel to remote");
1361: if(mode&ZMODEM)
1.1.1.2 ! root 1362: zmodem_send_zabort(&zm);
1.1 root 1363: xm.cancelled=FALSE;
1364: xmodem_cancel(&xm);
1365: break;
1366: }
1367:
1368: if(mode&XMODEM) /* maximum of one file */
1369: break;
1.1.1.2 ! root 1370: if((cps=(unsigned)(file_bytes/t))==0)
1.1 root 1371: cps=1;
1372: total_files--;
1373: total_bytes-=file_bytes;
1374: if(total_files>1 && total_bytes)
1.1.1.2 ! root 1375: lprintf(LOG_INFO,"Remaining - Time: %lu:%02lu Files: %u KBytes: %"PRIu64
1.1 root 1376: ,(total_bytes/cps)/60
1377: ,(total_bytes/cps)%60
1378: ,total_files
1379: ,total_bytes/1024
1380: );
1381: }
1382: return(!success); /* 0=success */
1383: }
1384:
1385: void bail(int code)
1386: {
1387: if(logfp!=NULL)
1388: fclose(logfp);
1389: if(pause_on_exit || (pause_on_abend && code!=0)) {
1390: printf("Hit enter to continue...");
1391: getchar();
1392: }
1393: exit(code);
1394: }
1395:
1396: static const char* usage=
1397: "usage: sexyz <socket> [-opts] <cmd> [file | path | @list]\n"
1398: "\n"
1399: #ifdef __unix__
1400: "socket = TCP socket descriptor (leave blank for stdio mode)\n"
1401: #else
1402: "socket = TCP socket descriptor\n"
1403: #endif
1404: "\n"
1.1.1.2 ! root 1405: "opts = -y allow overwriting of existing files when receiving\n"
1.1 root 1406: " -o disable Zmodem CRC-32 mode (use CRC-16)\n"
1407: " -s disable Zmodem streaming (Slow Zmodem)\n"
1.1.1.2 ! root 1408: " -k enable X/Ymodem-1K send mode\n"
! 1409: " -c enable Xmodem-CRC receive mode\n"
! 1410: " -g enable X/Ymodem-G receive mode (no error recovery)\n"
1.1 root 1411: " -2 set maximum Zmodem block size to 2K\n"
1412: " -4 set maximum Zmodem block size to 4K\n"
1413: " -8 set maximum Zmodem block size to 8K (ZedZap)\n"
1.1.1.2 ! root 1414: " -m# set maximum receive file size to # bytes (0=unlimited, default=%u)\n"
1.1 root 1415: " -! to pause after abnormal exit (error)\n"
1.1.1.2 ! root 1416: #ifdef __unix__
! 1417: " -telnet to enable Telnet mode (the default except in stdio mode)\n"
! 1418: #else
1.1 root 1419: " -telnet to enable Telnet mode (the default)\n"
1.1.1.2 ! root 1420: #endif
1.1 root 1421: " -rlogin or -ssh or -raw to disable Telnet mode\n"
1422: "\n"
1423: "cmd = v to display detailed version information\n"
1.1.1.2 ! root 1424: " sx to send Xmodem rx to receive Xmodem\n"
! 1425: " sX to send Xmodem-1K rc to receive Xmodem-CRC\n"
! 1426: " sy to send Ymodem ry to receive Ymodem\n"
! 1427: " sY to send Ymodem-1K rg to receive Ymodem-G\n"
! 1428: " sz to send Zmodem rz to receive Zmodem\n"
1.1 root 1429: "\n"
1430: "file = filename to send or receive\n"
1431: "path = directory to receive files into\n"
1432: "list = name of text file with list of filenames to send or receive\n";
1433:
1.1.1.2 ! root 1434: #ifdef __unix__
! 1435:
! 1436: struct termios tio_default; /* Initial term settings */
! 1437:
! 1438: #ifdef NEEDS_CFMAKERAW
! 1439: static void
! 1440: cfmakeraw(struct termios *t)
! 1441: {
! 1442: t->c_iflag &= ~(IMAXBEL|IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
! 1443: t->c_oflag &= ~OPOST;
! 1444: t->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
! 1445: t->c_cflag &= ~(CSIZE|PARENB);
! 1446: t->c_cflag |= CS8;
! 1447: }
! 1448: #endif
! 1449:
! 1450: static void fixterm(void)
! 1451: {
! 1452: tcsetattr(STDIN_FILENO,TCSANOW,&tio_default);
! 1453: }
! 1454:
! 1455: static void init_stdio(void)
! 1456: {
! 1457: struct termios tio_raw;
! 1458:
! 1459: if(isatty(STDERR_FILENO))
! 1460: fclose(stderr);
! 1461:
! 1462: if (isatty(STDIN_FILENO)) {
! 1463: tcgetattr(STDIN_FILENO,&tio_default);
! 1464: tio_raw = tio_default;
! 1465: /* cfmakeraw(&tio_raw); */
! 1466: tio_raw.c_iflag &= ~(IMAXBEL|IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
! 1467: tio_raw.c_oflag &= ~OPOST;
! 1468: tio_raw.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
! 1469: tio_raw.c_cflag &= ~(CSIZE|PARENB);
! 1470: tio_raw.c_cflag |= CS8;
! 1471: tcsetattr(STDIN_FILENO,TCSANOW,&tio_raw);
! 1472: setvbuf(stdout, NULL, _IOFBF, 0);
! 1473: atexit(fixterm);
! 1474: }
! 1475: }
! 1476:
! 1477: BOOL RingBufIsEmpty(void *buf)
! 1478: {
! 1479: return(RingBufFull(buf)==0);
! 1480: }
! 1481:
! 1482: #endif
! 1483:
1.1 root 1484: /***************/
1485: /* Entry Point */
1486: /***************/
1487: int main(int argc, char **argv)
1488: {
1489: char str[MAX_PATH+1];
1490: char fname[MAX_PATH+1];
1491: char ini_fname[MAX_PATH+1];
1492: char* p;
1493: char* arg;
1494: int i;
1495: int retval;
1496: uint fnames=0;
1497: FILE* fp;
1498: BOOL tcp_nodelay;
1499: char compiler[32];
1.1.1.2 ! root 1500: BOOL telnet_requested=FALSE;
1.1 root 1501: str_list_t fname_list;
1502:
1503: fname_list=strListInit();
1504:
1505: DESCRIBE_COMPILER(compiler);
1506:
1507: errfp=stderr;
1508: #ifdef __unix__
1509: statfp=stderr;
1510: #else
1511: statfp=stdout;
1512: #endif
1513:
1.1.1.2 ! root 1514: sscanf("$Revision: 1.132 $", "%*s %s", revision);
1.1 root 1515:
1.1.1.2 ! root 1516: fprintf(statfp,"\nSynchronet External X/Y/ZMODEM v%s-%s"
1.1 root 1517: " Copyright %s Rob Swindell\n\n"
1518: ,revision
1519: ,PLATFORM_DESC
1520: ,__DATE__+7
1521: );
1522:
1.1.1.2 ! root 1523: xmodem_init(&xm,NULL,&mode,lputs,xmodem_progress,send_byte,recv_byte,is_connected,NULL,flush);
! 1524: zmodem_init(&zm,NULL,lputs,zmodem_progress,send_byte,recv_byte,is_connected,NULL,data_waiting,flush);
! 1525: xm.log_level=&log_level;
! 1526: zm.log_level=&log_level;
1.1 root 1527:
1528: /* Generate path/sexyz[.host].ini from path/sexyz[.exe] */
1529: SAFECOPY(str,argv[0]);
1530: p=getfname(str);
1531: SAFECOPY(fname,p);
1532: *p=0;
1533: if((p=getfext(fname))!=NULL)
1534: *p=0;
1535: strcat(fname,".ini");
1536:
1537: iniFileName(ini_fname,sizeof(ini_fname),str,fname);
1538: if((fp=fopen(ini_fname,"r"))!=NULL)
1539: fprintf(statfp,"Reading %s\n",ini_fname);
1540:
1541: tcp_nodelay =iniReadBool(fp,ROOT_SECTION,"TCP_NODELAY",TRUE);
1542:
1543: telnet =iniReadBool(fp,ROOT_SECTION,"Telnet",TRUE);
1544: debug_tx =iniReadBool(fp,ROOT_SECTION,"DebugTx",FALSE);
1545: debug_rx =iniReadBool(fp,ROOT_SECTION,"DebugRx",FALSE);
1546: debug_telnet =iniReadBool(fp,ROOT_SECTION,"DebugTelnet",FALSE);
1547:
1548: pause_on_exit =iniReadBool(fp,ROOT_SECTION,"PauseOnExit",FALSE);
1549: pause_on_abend =iniReadBool(fp,ROOT_SECTION,"PauseOnAbend",FALSE);
1550:
1551: log_level =iniReadLogLevel(fp,ROOT_SECTION,"LogLevel",log_level);
1.1.1.2 ! root 1552: use_syslog =iniReadBool(fp,ROOT_SECTION,"SysLog",use_syslog);
1.1 root 1553:
1.1.1.2 ! root 1554: outbuf.highwater_mark =(ulong)iniReadBytes(fp,ROOT_SECTION,"OutbufHighwaterMark",1,1100);
1.1 root 1555: outbuf_drain_timeout =iniReadInteger(fp,ROOT_SECTION,"OutbufDrainTimeout",10);
1.1.1.2 ! root 1556: outbuf_size =(ulong)iniReadBytes(fp,ROOT_SECTION,"OutbufSize",1,16*1024);
1.1 root 1557:
1558: progress_interval =iniReadInteger(fp,ROOT_SECTION,"ProgressInterval",1);
1.1.1.2 ! root 1559: max_file_size =iniReadBytes(fp,ROOT_SECTION,"MaxFileSize",/* unit: */1,MAX_FILE_SIZE);
1.1 root 1560:
1561: if(iniReadBool(fp,ROOT_SECTION,"Debug",FALSE))
1562: log_level=LOG_DEBUG;
1563:
1564: xm.send_timeout =iniReadInteger(fp,"Xmodem","SendTimeout",xm.send_timeout); /* seconds */
1565: xm.recv_timeout =iniReadInteger(fp,"Xmodem","RecvTimeout",xm.recv_timeout); /* seconds */
1566: xm.byte_timeout =iniReadInteger(fp,"Xmodem","ByteTimeout",xm.byte_timeout); /* seconds */
1567: xm.ack_timeout =iniReadInteger(fp,"Xmodem","AckTimeout",xm.ack_timeout); /* seconds */
1.1.1.2 ! root 1568: xm.block_size =(ulong)iniReadBytes(fp,"Xmodem","BlockSize",1,xm.block_size); /* 128 or 1024 */
! 1569: xm.max_block_size =(ulong)iniReadBytes(fp,"Xmodem","MaxBlockSize",1,xm.max_block_size); /* 128 or 1024 */
1.1 root 1570: xm.max_errors =iniReadInteger(fp,"Xmodem","MaxErrors",xm.max_errors);
1571: xm.g_delay =iniReadInteger(fp,"Xmodem","G_Delay",xm.g_delay);
1.1.1.2 ! root 1572: xm.crc_mode_supported =iniReadBool(fp,"Xmodem","SendCRC",xm.crc_mode_supported);
! 1573: xm.g_mode_supported =iniReadBool(fp,"Xmodem","SendG",xm.g_mode_supported);
! 1574:
! 1575: xm.fallback_to_xmodem =iniReadInteger(fp,"Ymodem","FallbackToXmodem", xm.fallback_to_xmodem);
1.1 root 1576:
1577: zm.init_timeout =iniReadInteger(fp,"Zmodem","InitTimeout",zm.init_timeout); /* seconds */
1578: zm.send_timeout =iniReadInteger(fp,"Zmodem","SendTimeout",zm.send_timeout); /* seconds */
1579: zm.recv_timeout =iniReadInteger(fp,"Zmodem","RecvTimeout",zm.recv_timeout); /* seconds */
1580: zm.crc_timeout =iniReadInteger(fp,"Zmodem","CrcTimeout",zm.crc_timeout); /* seconds */
1.1.1.2 ! root 1581: zm.block_size =(ulong)iniReadBytes(fp,"Zmodem","BlockSize",1,zm.block_size); /* 1024 */
! 1582: zm.max_block_size =(ulong)iniReadBytes(fp,"Zmodem","MaxBlockSize",1,zm.max_block_size); /* 1024 or 8192 */
1.1 root 1583: zm.max_errors =iniReadInteger(fp,"Zmodem","MaxErrors",zm.max_errors);
1.1.1.2 ! root 1584: zm.recv_bufsize =(ulong)iniReadBytes(fp,"Zmodem","RecvBufSize",1,0);
1.1 root 1585: zm.no_streaming =!iniReadBool(fp,"Zmodem","Streaming",TRUE);
1586: zm.want_fcs_16 =!iniReadBool(fp,"Zmodem","CRC32",TRUE);
1587: zm.escape_telnet_iac =iniReadBool(fp,"Zmodem","EscapeTelnetIAC",TRUE);
1588: zm.escape_8th_bit =iniReadBool(fp,"Zmodem","Escape8thBit",FALSE);
1589: zm.escape_ctrl_chars =iniReadBool(fp,"Zmodem","EscapeCtrlChars",FALSE);
1590:
1591: dszlog_path =iniReadBool(fp,"DSZLOG","Path",TRUE);
1592: dszlog_short =iniReadBool(fp,"DSZLOG","Short",FALSE);
1593: dszlog_quotes =iniReadBool(fp,"DSZLOG","Quotes",FALSE);
1594:
1595: if(fp!=NULL)
1596: fclose(fp);
1597:
1598: if(zm.recv_bufsize > 0xffff)
1599: zm.recv_bufsize = 0xffff;
1600:
1601: if(outbuf_size < MIN_OUTBUF_SIZE)
1602: outbuf_size = MIN_OUTBUF_SIZE;
1603: else if(outbuf_size > MAX_OUTBUF_SIZE)
1604: outbuf_size = MAX_OUTBUF_SIZE;
1605:
1606: fprintf(statfp,"Output buffer size: %u\n", outbuf_size);
1607: RingBufInit(&outbuf, outbuf_size);
1608:
1609: #if !defined(RINGBUF_EVENT)
1610: outbuf_empty=CreateEvent(NULL,/* ManualReset */TRUE, /*InitialState */TRUE,NULL);
1.1.1.2 ! root 1611: #ifdef __unix__
! 1612: outbuf_empty->cbdata=&outbuf;
! 1613: outbuf_empty->verify=RingBufIsEmpty;
! 1614: #endif
1.1 root 1615: #endif
1616:
1617: #if 0
1618: if(argc>1) {
1619: fprintf(statfp,"Command line: ");
1620: for(i=1;i<argc;i++)
1621: fprintf(statfp,"%s ",argv[i]);
1622: fprintf(statfp,"\n",statfp);
1623: }
1624: #endif
1625:
1626:
1627: for(i=1;i<argc;i++) {
1628:
1629: if(sock==INVALID_SOCKET && isdigit(argv[i][0])) {
1630: sock=atoi(argv[i]);
1631: continue;
1632: }
1633:
1634: if(!(mode&(SEND|RECV))) {
1635: if(toupper(argv[i][0])=='S' || toupper(argv[i][0])=='R') { /* cmd */
1636: if(toupper(argv[i][0])=='R')
1637: mode|=RECV;
1638: else
1639: mode|=SEND;
1640:
1641: switch(argv[i][1]) {
1642: case 'c':
1643: case 'C':
1644: mode|=XMODEM|CRC;
1645: break;
1646: case 'x':
1.1.1.2 ! root 1647: xm.block_size=XMODEM_MIN_BLOCK_SIZE;
1.1 root 1648: case 'X':
1649: mode|=XMODEM;
1650: break;
1651: case 'b': /* sz/rz compatible */
1652: case 'B':
1653: case 'y':
1.1.1.2 ! root 1654: xm.block_size=XMODEM_MIN_BLOCK_SIZE;
1.1 root 1655: case 'Y':
1656: mode|=(YMODEM|CRC);
1657: break;
1.1.1.2 ! root 1658: case 'k': /* Ymodem-Checksum for debug/test purposes only */
! 1659: mode|=YMODEM;
! 1660: break;
1.1 root 1661: case 'g':
1662: case 'G':
1663: mode|=(YMODEM|CRC|GMODE);
1664: break;
1665: case 'z':
1666: case 'Z':
1667: mode|=(ZMODEM|CRC);
1668: break;
1669: default:
1670: fprintf(statfp,"Unrecognized command '%s'\n\n",argv[i]);
1.1.1.2 ! root 1671: fprintf(statfp,usage,MAX_FILE_SIZE);
1.1 root 1672: bail(1);
1.1.1.2 ! root 1673: return -1;
1.1 root 1674: }
1675: continue;
1676: }
1677:
1678: if(toupper(argv[i][0])=='V') {
1679:
1680: fprintf(statfp,"%-8s %s\n",getfname(__FILE__) ,revision);
1681: fprintf(statfp,"%-8s %s\n",getfname(xmodem_source()),xmodem_ver(str));
1682: fprintf(statfp,"%-8s %s\n",getfname(zmodem_source()),zmodem_ver(str));
1683: #ifdef _DEBUG
1684: fprintf(statfp,"Debug\n");
1685: #endif
1686: fprintf(statfp,"Compiled %s %.5s with %s\n",__DATE__,__TIME__,compiler);
1687: fprintf(statfp,"%s\n",os_version(str));
1688: bail(0);
1.1.1.2 ! root 1689: return 0;
1.1 root 1690: }
1691:
1692: arg=argv[i];
1693: if(*arg=='-') {
1694: while(*arg=='-')
1695: arg++;
1696: if(stricmp(arg,"telnet")==0) {
1.1.1.2 ! root 1697: telnet_requested=TRUE;
1.1 root 1698: telnet=TRUE;
1699: continue;
1700: }
1701: if(stricmp(arg,"rlogin")==0 || stricmp(arg,"ssh")==0 || stricmp(arg,"raw")==0) {
1.1.1.2 ! root 1702: telnet_requested=FALSE;
1.1 root 1703: telnet=FALSE;
1704: continue;
1705: }
1706: if(stricmp(arg,"debug")==0) {
1707: log_level=LOG_DEBUG;
1708: continue;
1709: }
1.1.1.2 ! root 1710: if(stricmp(arg,"syslog")==0) {
! 1711: use_syslog=TRUE;
! 1712: continue;
! 1713: }
1.1 root 1714: if(stricmp(arg,"quotes")==0) {
1715: dszlog_quotes=TRUE;
1716: continue;
1717: }
1718: switch(toupper(*arg)) {
1719: case 'K': /* sz/rz compatible */
1.1.1.2 ! root 1720: xm.block_size=XMODEM_MAX_BLOCK_SIZE;
1.1 root 1721: break;
1722: case 'C': /* sz/rz compatible */
1723: mode|=CRC;
1724: break;
1725: case '2':
1726: zm.max_block_size=2048;
1727: break;
1728: case '4':
1729: zm.max_block_size=4096;
1730: break;
1731: case '8': /* ZedZap */
1732: zm.max_block_size=8192;
1733: break;
1734: case 'O': /* disable Zmodem CRC-32 */
1735: zm.want_fcs_16=TRUE;
1736: break;
1737: case 'S': /* disable Zmodem streaming */
1738: zm.no_streaming=TRUE;
1739: break;
1.1.1.2 ! root 1740: case 'G': /* Ymodem-G or Xmodem-G (a.k.a. Qmodem-G) */
! 1741: mode|=(GMODE|CRC);
1.1 root 1742: break;
1743: case 'Y':
1744: mode|=OVERWRITE;
1745: break;
1746: case '!':
1747: pause_on_abend=TRUE;
1748: break;
1.1.1.2 ! root 1749: case 'M': /* MaxFileSize */
! 1750: max_file_size=strtoul(arg++,NULL,0); /* TODO: use strtoull() ? */
! 1751: break;
1.1 root 1752: }
1753: }
1754: }
1755:
1756: else if((argv[i][0]=='+' || argv[i][0]=='@') && fexist(argv[i]+1)) {
1757: if(mode&RECVDIR) {
1758: fprintf(statfp,"!Cannot specify both directory and filename\n");
1759: bail(1);
1.1.1.2 ! root 1760: return -1;
1.1 root 1761: }
1762: sprintf(str,"%s",argv[i]+1);
1763: if((fp=fopen(str,"r"))==NULL) {
1764: fprintf(statfp,"!Error %d opening filelist: %s\n",errno,str);
1765: bail(1);
1.1.1.2 ! root 1766: return -1;
1.1 root 1767: }
1768: while(!feof(fp) && !ferror(fp)) {
1769: if(!fgets(str,sizeof(str),fp))
1770: break;
1771: truncsp(str);
1772: strListAppend(&fname_list,strdup(str),fnames++);
1773: }
1774: fclose(fp);
1775: }
1776:
1777: else if(mode&(SEND|RECV)){
1778: if(isdir(argv[i])) { /* is a directory */
1779: if(mode&RECVDIR) {
1780: fprintf(statfp,"!Only one directory can be specified\n");
1781: bail(1);
1.1.1.2 ! root 1782: return -1;
1.1 root 1783: }
1784: if(fnames) {
1785: fprintf(statfp,"!Cannot specify both directory and filename\n");
1786: bail(1);
1.1.1.2 ! root 1787: return -1;
1.1 root 1788: }
1789: if(mode&SEND) {
1790: fprintf(statfp,"!Cannot send directory '%s'\n",argv[i]);
1791: bail(1);
1.1.1.2 ! root 1792: return -1;
1.1 root 1793: }
1794: mode|=RECVDIR;
1795: }
1796: strListAppend(&fname_list,argv[i],fnames++);
1797: }
1798: }
1799:
1.1.1.2 ! root 1800: if(max_file_size)
! 1801: fprintf(statfp,"Maximum receive file size: %"PRIi64"\n", max_file_size);
! 1802:
! 1803: if(!(mode&(SEND|RECV))) {
! 1804: fprintf(statfp,"!No command specified\n\n");
! 1805: fprintf(statfp,usage,MAX_FILE_SIZE);
! 1806: bail(1);
! 1807: return -1;
! 1808: }
! 1809:
! 1810: if(mode&(SEND|XMODEM) && !fnames) { /* Sending with any or recv w/Xmodem */
! 1811: fprintf(statfp,"!Must specify filename or filelist\n\n");
! 1812: fprintf(statfp,usage,MAX_FILE_SIZE);
! 1813: bail(1);
! 1814: return -1;
! 1815: }
1.1 root 1816:
1817: if(sock==INVALID_SOCKET || sock<1) {
1818: #ifdef __unix__
1819: if(STDOUT_FILENO > STDIN_FILENO)
1820: sock=STDOUT_FILENO;
1821: else
1822: sock=STDIN_FILENO;
1823: stdio=TRUE;
1.1.1.2 ! root 1824:
1.1 root 1825: fprintf(statfp,"No socket descriptor specified, using STDIO\n");
1.1.1.2 ! root 1826: if(!telnet_requested)
! 1827: telnet=FALSE;
! 1828: init_stdio();
1.1 root 1829: #else
1830: fprintf(statfp,"!No socket descriptor specified\n\n");
1.1.1.2 ! root 1831: fprintf(errfp,usage,MAX_FILE_SIZE);
1.1 root 1832: bail(1);
1.1.1.2 ! root 1833: return -1;
1.1 root 1834: #endif
1835: }
1836: #ifdef __unix__
1837: else
1838: statfp=stdout;
1839: #endif
1840:
1.1.1.2 ! root 1841: if(!telnet)
! 1842: zm.escape_telnet_iac = FALSE;
1.1 root 1843:
1.1.1.2 ! root 1844: zm.max_file_size = max_file_size;
1.1 root 1845:
1846: /* Code disabled. Why? ToDo */
1847: /* if(mode&RECVDIR)
1848: backslash(fname[0]); */
1849:
1850: if(!winsock_startup())
1851: bail(-1);
1852:
1853: /* Enable the Nagle Algorithm */
1854: #ifdef __unix__
1855: if(!stdio) {
1856: #endif
1857: lprintf(LOG_DEBUG,"Setting TCP_NODELAY to %d",tcp_nodelay);
1858: setsockopt(sock,IPPROTO_TCP,TCP_NODELAY,(char*)&tcp_nodelay,sizeof(tcp_nodelay));
1859: #ifdef __unix__
1860: }
1861: #endif
1862:
1.1.1.2 ! root 1863: /* Set non-blocking mode */
! 1864: #ifdef __unix__
! 1865: if(stdio) {
! 1866: fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK);
! 1867: }
! 1868: else
! 1869: #endif
! 1870: {
! 1871: i=1;
! 1872: ioctlsocket(sock, FIONBIO, &i);
! 1873: }
! 1874:
1.1 root 1875: if(!socket_check(sock, NULL, NULL, 0)) {
1876: lprintf(LOG_WARNING,"No socket connection");
1877: bail(-1);
1.1.1.2 ! root 1878: return -1;
1.1 root 1879: }
1880:
1881: if((dszlog=getenv("DSZLOG"))!=NULL) {
1882: if((logfp=fopen(dszlog,"w"))==NULL) {
1883: lprintf(LOG_WARNING,"Error %d opening DSZLOG file: %s",errno,dszlog);
1884: bail(-1);
1.1.1.2 ! root 1885: return -1;
1.1 root 1886: }
1887: }
1888:
1889: /* Install Ctrl-C/Break signal handler here */
1890: #if defined(_WIN32)
1891: SetConsoleCtrlHandler(ControlHandler, TRUE /* Add */);
1892: #elif defined(__unix__)
1893: signal(SIGQUIT,break_handler);
1894: signal(SIGINT,break_handler);
1895: signal(SIGTERM,break_handler);
1896:
1897: signal(SIGHUP,SIG_IGN);
1898:
1899: /* Don't die on SIGPIPE */
1900: signal(SIGPIPE,SIG_IGN);
1901: #endif
1902:
1903: #if !SINGLE_THREADED
1904: _beginthread(output_thread,0,NULL);
1905: #endif
1906:
1907: if(mode&RECV)
1908: retval=receive_files(fname_list, fnames);
1909: else
1910: retval=send_files(fname_list, fnames);
1911:
1912: #if !SINGLE_THREADED
1913: lprintf(LOG_DEBUG,"Waiting for output buffer to empty... ");
1.1.1.2 ! root 1914: if(RingBufFull(&outbuf)) {
! 1915: #if !defined(RINGBUF_EVENT)
! 1916: ResetEvent(outbuf_empty);
! 1917: #endif
! 1918: if(WaitForEvent(outbuf_empty,5000)!=WAIT_OBJECT_0)
! 1919: lprintf(LOG_DEBUG,"FAILURE");
! 1920: }
1.1 root 1921: #endif
1922:
1923: terminate=TRUE; /* stop output thread */
1924: /* Code disabled. Why? ToDo */
1925: /* sem_post(outbuf.sem);
1926: sem_post(outbuf.highwater_sem); */
1927:
1928: fprintf(statfp,"Exiting - Error level: %d, flows: %u, select_errors=%u"
1929: ,retval, flows, select_errors);
1930: fprintf(statfp,"\n");
1931:
1932: bail(retval);
1.1.1.2 ! root 1933: return retval;
1.1 root 1934: }
1935:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.