From 6f4ad3b626c30d7d8bbe128bda2991b7169e59d1 Mon Sep 17 00:00:00 2001 From: "itspy.wei" Date: Thu, 3 Mar 2011 07:39:36 +0000 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20zmodem?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: https://rt-thread.googlecode.com/svn/trunk@1302 bbd45198-f89e-11dd-88c7-29a3b14d5316 --- components/utilities/ZMODEM/RBSB.C | 24 + components/utilities/ZMODEM/RZ.1 | 269 ++++ components/utilities/ZMODEM/RZ.C | 1104 +++++++++++++ components/utilities/ZMODEM/RZ.H | 77 + components/utilities/ZMODEM/SZ.1 | 336 ++++ components/utilities/ZMODEM/SZ.C | 1168 ++++++++++++++ components/utilities/ZMODEM/ZM.C | 480 ++++++ components/utilities/ZMODEM/ZMODEM.DOC | 2056 ++++++++++++++++++++++++ components/utilities/ZMODEM/ZMODEM.H | 107 ++ 9 files changed, 5621 insertions(+) create mode 100644 components/utilities/ZMODEM/RBSB.C create mode 100644 components/utilities/ZMODEM/RZ.1 create mode 100644 components/utilities/ZMODEM/RZ.C create mode 100644 components/utilities/ZMODEM/RZ.H create mode 100644 components/utilities/ZMODEM/SZ.1 create mode 100644 components/utilities/ZMODEM/SZ.C create mode 100644 components/utilities/ZMODEM/ZM.C create mode 100644 components/utilities/ZMODEM/ZMODEM.DOC create mode 100644 components/utilities/ZMODEM/ZMODEM.H diff --git a/components/utilities/ZMODEM/RBSB.C b/components/utilities/ZMODEM/RBSB.C new file mode 100644 index 0000000000..2a1394e273 --- /dev/null +++ b/components/utilities/ZMODEM/RBSB.C @@ -0,0 +1,24 @@ +/* -rev 05-12-86 + * mode function and most of the rest of the system dependent + * stuff for rb.c and sb.c This file is #included so the includer + * can set parameters such as HOWMANY. + */ + +int iofd = 0; /* File descriptor for ioctls & reads */ + +/* + * mode(n) + * 2: set a cbreak, XON/XOFF control mode if using Pro-YAM's -g option + * 1: save old tty stat, set raw mode + * 0: restore original tty mode + */ +int mode(int n) +{ + return 0; +} + +int sendbrk() +{ + //ioctl(iofd, TCSBRK, 0); + return 0; +} diff --git a/components/utilities/ZMODEM/RZ.1 b/components/utilities/ZMODEM/RZ.1 new file mode 100644 index 0000000000..a0869b8c36 --- /dev/null +++ b/components/utilities/ZMODEM/RZ.1 @@ -0,0 +1,269 @@ +'\" Revision Level +'\" Last Delta 05-19-86 +.TH RZ 1 OMEN +.SH NAME +rb, rz \- XMODEM, YMODEM, ZMODEM (Batch) file receive +.SH SYNOPSIS +.B rz +.RB [\- "\ 1bquv" ] +.br +.B rb +.RB [\- "\ 1bquv" ] +.br +.B rz +.RB [\- "\ 1bcquv" ] +.I file +.br +.RB [ \- ][ v ] rzCOMMAND +.SH DESCRIPTION +This program uses error correcting protocol to receive +files over a serial port from a variety of programs running under +PC-DOS, CP/M, +.SM Unix, +and other operating systems. + +The first form of +.B rz +(Receive Batch) +receives files with ZMODEM batch protocol. +If the sending program does not support ZMODEM, +.B rz +steps down to YMODEM protocol +after 50 seconds. +This delay can be eliminated by calling the program as +.I rb . + +.B Rb +accepts either standard 128 byte sectors or +1024 byte sectors +(YAM +.B -k +option). +The user should determine experimentally +the conditions under which use of 1k blocks +actually improves throughput without causing +problems. + +Normally, the file contents are converted to +.SM Unix +conventions by stripping carriage returns and all characters +beginning with Control Z (CP/M end of file). +If the raw pathname ends in +".A", +".ARC", +".CCC", +".CL", +".CMD", +".COM", +".CRL", +".DAT", +".DIR", +".EXE", +".O", +".OBJ", +".OVL", +".PAG", +".REL", +".SAV", +".SUB", +".SWP", +".SYS", +".TAR", +".UTL", +".a", +".o", +".tar", +or if the first packet contains +data that suggest a binary file +(parity bits or characters in the range 000 to 006 before the first ^Z), +or if the file mode is transmitted and the 0100000 +bit is set, that file will be received in binary mode anyway. +Otherwise, +if the raw pathname ends in .MSG, or .TXT, an existing file will +be appended to rather than replaced. + +If extended file information (file length, etc.) +is received, +the file length controls the number of bytes written to +the output dataset (YMODEM only), +and the modify time and file mode +(iff non zero) +are set accordingly. + +If no extended file information is received, +slashes in the pathname are changed to underscore, +and any trailing period in the pathname is eliminated. +This conversion is useful for files received from CP/M systems. +Normally, each file name is converted to lower case +unless it contains one or more lower case letters. + + +The second form of +.B rz +receives a single +.I file +with XMODEM protocol. +The user must supply the file name to both sending and receiving programs. + + +The third form of +.B rz +is invoked as +.B rzCOMMAND +(with an optional leading \- as generated by login(1)). +For each received file, +rz will pipe the file to ``COMMAND filename'' +where filename is the name of the transmitted file +with the file contents as standard input. + +Each file transfer is acknowledged when COMMAND exits with 0 status. +A non zero exit status terminates transfers. + +A typical use for this form is +.I rzrmail +which calls rmail(1) +to post mail to the user specified by the transmitted file name. +For example, sending the file "caf" from a PC-DOS system to +.I rzrmail +on a +.SM Unix +system +would result in the contents of the DOS file "caf" being mailed to user "caf". + +On some +.SM Unix +systems, the login directory must contain a link to +COMMAND as login sets SHELL=rsh which disallows absolute +pathnames. +If invoked with a leading ``v'', +.B rz +will report progress to LOGFILE. +The following entry works for +.SM Unix +3.0: +.ce +rzrmail::5:1::/bin:/usr/local/rzrmail +If the SHELL environment variable includes +.I "rsh" +or +.I "rksh" +(restricted shell), +rz will not accept absolute pathnames +or references to a parent directory, +will not modify an existing file, and +removes any files received in error. + +If +.B rz +is invoked with stdout and stderr to different datasets, +Verbose is set to 2, causing frame by frame progress reports +to stderr. +This may be disabled with the +.B q +option. + +.PP +The meanings of the available options are: +.PP +.PD 0 +.TP +.B 1 +Use file descriptor 1 for ioctls and reads (Unix only). +By default, file descriptor 0 is used. +This option allows +.B rz +to be used with the +.I cu +~$ +command. +.TP +.B b +Transfer all files in binary +(tell it like it is) +mode. +This option disables file append. +.TP +.B c +Request 16 bit CRC +(XMODEM file transfers default to 8 bit checksum). +Batch transfers use 16 bit CRC. +.TP +.B D +Output file data to /dev/null; for testing. +.TP +.B q +Quiet suppresses verbosity. +.TP +.B v +Verbose +causes a list of file +names to be appended to +/tmp/rzlog . +More v's generate more output. +.TP +.B u +Retain upper case letters in file names. +.PD +.SH EXAMPLES +.ne 6 +.RE +(Pro-YAM command) +.RS +.I +.br +YAM Command: +.I "sz *.h *.c" +.br +(This automatically invokes +.I rz +on the connected system.) +.RE +.SH SEE ALSO +ZMODEM.DOC, +YMODEM.DOC, +IMP(CP/M), +cu(1), +Professional-YAM manual, +sz(omen), +usq(omen), +undos(omen) + +Compile time options required +for various operating systems are described in the +source file. +.SH BUGS +Pathnames are restricted to 127 characters. +In XMODEM single file mode, the pathname given on the command line +is still processed as described above. +The CR/LF to NL translation merely deletes CR\'s; +undos(omen) performs a more intelligent translation. +.SH "VMS VERSION" +Some of the #includes with file names enclosed with angle brackets <> +may need to have the angle brackets changed to "", or vice versa. + +The VMS version does not set binary mode according to the incoming +file type. +Non binary file processing consists of stripping all characters beginning +with CPMEOF (^Z). + +The VMS version does not set the file time. + +At high speeds, +VMS sometimes loses incoming characters, resulting in retries +and degradation of throughput. + +The mysterious +VMS C Standard I/O Package and RMS may interact to modify +file contents unexpectedly. + +The VMS version does not support invocation as +.B rzCOMMAND . +ZMODEM has not yet been implemented on the VMS version. +.SH "ZMODEM CAPABILITIES" +.B Rz +supports incoming ZMODEM binary (-b), ASCII (-a), and append (-+) +requests, and ZMODEM command execution. +.SH FILES +rz.c, rbsb.c, zm.c, zmodem.h source files. + +/tmp/rzlog stores debugging output generated with -vv option. diff --git a/components/utilities/ZMODEM/RZ.C b/components/utilities/ZMODEM/RZ.C new file mode 100644 index 0000000000..fdc1ae247d --- /dev/null +++ b/components/utilities/ZMODEM/RZ.C @@ -0,0 +1,1104 @@ +#define VERSION "1.03 05-18-86" +#define PUBDIR "/usr/spool/uucppublic" + +/*% cc -DNFGVMIN -K -O % -o rz; size rz + * + * rz.c By Chuck Forsberg + * + * cc -O rz.c -o rz USG (3.0) Unix + * cc -O -DV7 rz.c -o rz Unix V7, BSD 2.8 - 4.3 + * + * ln rz rb For either system + * + * ln rz /usr/bin/rbrmail For remote mail. Make this the + * login shell. rbrmail then calls + * rmail(1) to deliver mail. + * + * Unix is a trademark of Western Electric Company + * + * A program for Unix to receive files and commands from computers running + * Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM. + * rz uses Unix buffered input to reduce wasted CPU time. + * + * Iff the program is invoked by rzCOMMAND, output is piped to + * "COMMAND filename" + * + * Some systems (Venix, Coherent, Regulus) may not support tty raw mode + * read(2) the same way as Unix. ONEREAD must be defined to force one + * character reads for these systems. Added 7-01-84 CAF + * + * Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF + * + * NFGVMIN Added 1-13-85 CAF for PC-AT Xenix systems where c_cc[VMIN] + * doesn't seem to work (even though it compiles without error!). + * + * USG UNIX (3.0) ioctl conventions courtesy Jeff Martin + */ +#define zperr vfile + +#include "rtthread.h" +#include "finsh.h" +#include "shell.h" +#include"rtdef.h" +#include +#include +#include + + +#define OK 0 +#define FALSE 0 +#define TRUE 1 +#define ERROR (-1) + +#define HOWMANY 133 +int Zmodem=0; /* ZMODEM protocol requested */ +int Nozmodem = 0; /* If invoked as "rb" */ +unsigned Baudrate; +#include "rbsb.c" /* most of the system dependent stuff here */ + + +int fout; + +/* + * Routine to calculate the free bytes on the current file system + * ~0 means many free bytes (unknown) + */ +long getfree() +{ + return(~0L); /* many free bytes ... */ +} + +char *Extensions[] = { +".A", +".ARC", +".CCC", +".CL", +".CMD", +".COM", +".CRL", +".DAT", +".DIR", +".EXE", +".O", +".OBJ", +".OVL", +".PAG", +".REL", +".SAV", +".SUB", +".SWP", +".SYS", +".TAR", +".UTL", +".a", +".arc", +".com", +".dat", +".o", +".obj", +".ovl", +".sys", +".tar", +"" +}; + +/* Ward Christensen / CP/M parameters - Don't change these! */ +#define ENQ 005 +#define CAN ('X'&037) +#define XOFF ('s'&037) +#define XON ('q'&037) +#define SOH 1 +#define STX 2 +#define EOT 4 +#define ACK 6 +#define NAK 025 +#define CPMEOF 032 +#define WANTCRC 0103 /* send C not NAK to get crc not checksum */ +#define TIMEOUT (-2) +#define ERRORMAX 5 +#define RETRYMAX 5 +#define WCEOT (-10) +#define SECSIZ 128 /* cp/m's Magic Number record size */ +#define PATHLEN 257 /* ready for 4.2 bsd ? */ +#define KSIZE 1024 /* record size with k option */ +#define UNIXFILE 0x8000 /* happens to the the S_IFREG file mask bit for stat */ + +int Lastrx; +int Crcflg; +int Firstsec; +int Eofseen; /* indicates cpm eof (^Z) has been received */ +int errors; +int Restricted=0; /* restricted; no /.. or ../ in filenames */ +int Badclose = 0; /* Error on last close */ +#define ONEREAD 1 +#ifdef ONEREAD +/* Sorry, Regulus and some others don't work right in raw mode! */ +int Readnum = 1; /* Number of bytes to ask for in read() from modem */ +#else +int Readnum = KSIZE; /* Number of bytes to ask for in read() from modem */ +#endif + +#define DEFBYTL 2000000000L /* default rx file size */ +long Bytesleft; /* number of bytes of incoming file left */ +long Modtime; /* Unix style mod time for incoming file */ +short Filemode; /* Unix style mode for incoming file */ +char Pathname[PATHLEN]; +char *Progname; /* the name by which we were called */ + +int Batch=0; +int Wcsmask=0377; +int Topipe=0; +int MakeLCPathname=TRUE; /* make received pathname lower case */ +int Verbose=0; +int Quiet=0; /* overrides logic that would otherwise set verbose */ +int Nflag = 0; /* Don't really transfer files */ +int Rxbinary=FALSE; /* receive all files in bin mode */ +int Thisbinary; /* current file is to be received in bin mode */ +int Blklen; /* record length of received packets */ +char secbuf[KSIZE]; +char linbuf[KSIZE]; +int Lleft=0; /* number of characters in linbuf */ + +char zconv; /* ZMODEM file conversion request */ +char zmanag; /* ZMODEM file management request */ +char ztrans; /* ZMODEM file transport request */ + + +int purgeline(void); +unsigned short int updcrc(int c, int crc); +int procheader(char *name); +int report(int sct); +int tryz(void); +int rzfiles(void); +int rzfile(void); +int closeit(void); +int zmputs(char *s); +int ackbibi(void); +int wcreceive(int argc, char **argp); +int wcrxpn(char *rpn); +int wcrx(void); +int wcgetsec(char *rxbuf, int maxtime); +int readline(int timeout); +int putsec(char *buf, int n); +int sendline(int c); +int xsendline(int c); +int log(const char *s,...); +int bttyout(int c); +int flushmo(void); +int canit(void); +int sys2(char *s); +int exec2(char *s); + +#include "zm.c" + + +/* called by signal interrupt or terminate to clean things up */ +int bibi(int n) +{ + if (Zmodem) + zmputs(Attn); + canit(); + mode(0); + return 0; +} + +int zrmain(void) +{ + if (wcreceive(0, 0)==ERROR) { + canit(); + zperr("received error,exit\n"); + return 1; + } + return 0; +} + + +int usage(void) +{ + //rt_kprintf("%s %s for %s by Chuck Forsberg\n", + // Progname, VERSION, OS); + //rt_kprintf("Usage: rz [-1buv] (ZMODEM Batch)\n"); + //rt_kprintf("or rb [-1buv] (YMODEM Batch)\n"); + //rt_kprintf("or rz [-1bcv] file (XMODEM)\n"); + //rt_kprintf(" -1 For cu(1): Use fd 1 for input\n"); + //rt_kprintf(" -b Binary transfer for all files\n"); + //rt_kprintf(" -u Allow all UPPER CASE names\n"); + //rt_kprintf(" -v Verbose more v's give more info\n"); + //rt_kprintf(" -c Use 16 bit CRC (XMODEM)\n"); + //exit(1); + return 0; +} +/* + * Debugging information output interface routine + */ +/* VARARGS1 */ +void vfile(const char *fmt,...) +{ + return; +} + +/* + * Let's receive something already. + */ +int wcreceive(int argc, char **argp) +{ + int c; + + if (Batch || argc==0) { + Crcflg=(Wcsmask==0377); + if ( !Quiet) + rt_kprintf("\nrz: ready...\n"); + c = tryz(); + if (c) { + if (c == ZCOMPL) + return OK; + if (c == ERROR) + goto fubar; + c = rzfiles(); + if (c) + goto fubar; + } else { + for (;;) { + if (wcrxpn(secbuf)== ERROR) + goto fubar; + if (secbuf[0]==0) + return OK; + if (procheader(secbuf) == ERROR) + goto fubar; + if (wcrx()==ERROR) + goto fubar; + } + } + } else { + Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L; + + strcpy(Pathname, *argp); + //checkpath(Pathname); + //rt_kprintf(stderr, "\nrz: ready to receive %s ", Pathname); + //if ((fout=fopen(Pathname, "w")) == NULL) + // return ERROR; + if (wcrx()==ERROR) + goto fubar; + } + return OK; +fubar: + canit(); + if (Topipe && fout) { + close(fout); return ERROR; + } + if (fout) + close(fout); + if (Restricted) { + unlink(Pathname); + rt_kprintf("\r\nrz: %s removed.\r\n", Pathname); + } + return ERROR; +} + + +/* + * Fetch a pathname from the other end as a C ctyle ASCIZ string. + * Length is indeterminate as long as less than Blklen + * A null string represents no more files (YMODEM) + */ +int wcrxpn(char *rpn) +{ + int c; + +#ifdef NFGVMIN + readline(1); +#else + purgeline(); +#endif + +et_tu: + Firstsec=TRUE; Eofseen=FALSE; + sendline(Crcflg?WANTCRC:NAK); + Lleft=0; /* Do read next time ... */ + while ((c = wcgetsec(rpn, 100)) != 0) { + log( "Pathname fetch returned %d\n", c); + if (c == WCEOT) { + sendline(ACK); + Lleft=0; /* Do read next time ... */ + readline(1); + goto et_tu; + } + return ERROR; + } + sendline(ACK); + return OK; +} + +/* + * Adapted from CMODEM13.C, written by + * Jack M. Wierda and Roderick W. Hart + */ + +int wcrx(void) +{ + register int sectnum, sectcurr; + register char sendchar; + register char *p; + int cblklen; /* bytes to dump this block */ + + Firstsec=TRUE;sectnum=0; Eofseen=FALSE; + sendchar=Crcflg?WANTCRC:NAK; + + for (;;) { + sendline(sendchar); /* send it now, we're ready! */ + Lleft=0; /* Do read next time ... */ + sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130); + report(sectcurr); + if (sectcurr==(sectnum+1 &Wcsmask)) { + + if (sectnum==0 && !Thisbinary) { + p=secbuf; sectcurr=Blklen; + if (*p == 032) /* A hack for .arc files */ + goto binbin; + for (; *p != 032 && --sectcurr>=0; ++p) + if (*p < 07 || (*p & 0200)) { +binbin: + Thisbinary++; + if (Verbose) + rt_kprintf("Changed to BIN\n"); + break; + } + } + sectnum++; + cblklen = Bytesleft>Blklen ? Blklen:Bytesleft; + if (putsec(secbuf, cblklen)==ERROR) + return ERROR; + if ((Bytesleft-=cblklen) < 0) + Bytesleft = 0; + sendchar=ACK; + } + else if (sectcurr==(sectnum&Wcsmask)) { + log( "Received dup Sector\n"); + sendchar=ACK; + } + else if (sectcurr==WCEOT) { + if (closeit()) + return ERROR; + sendline(ACK); + Lleft=0; /* Do read next time ... */ + return OK; + } + else if (sectcurr==ERROR) + return ERROR; + else { + log( "Sync Error\n"); + return ERROR; + } + } +} + +/* + * Wcgetsec fetches a Ward Christensen type sector. + * Returns sector number encountered or ERROR if valid sector not received, + * or CAN CAN received + * or WCEOT if eot sector + * time is timeout for first char, set to 4 seconds thereafter + ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK ************** + * (Caller must do that when he is good and ready to get next sector) + */ + +int wcgetsec(char *rxbuf, int maxtime) +{ + int checksum, wcj, firstch; + unsigned short oldcrc; + char *p; + int sectcurr; + + for (Lastrx=errors=0; errors=0; ) { + if ((firstch=readline(1)) < 0) + goto bilge; + oldcrc=updcrc(firstch, oldcrc); + checksum += (*p++ = firstch); + } + if ((firstch=readline(1)) < 0) + goto bilge; + if (Crcflg) { + oldcrc=updcrc(firstch, oldcrc); + if ((firstch=readline(1)) < 0) + goto bilge; + oldcrc=updcrc(firstch, oldcrc); + if (oldcrc & 0xFFFF) + log("CRC=0%o\n", oldcrc); + else { + Firstsec=FALSE; + return sectcurr; + } + } + else if (((checksum-firstch)&Wcsmask)==0) { + Firstsec=FALSE; + return sectcurr; + } + else + log( "Checksum Error\n"); + } + else + log("Sector number garbled 0%o 0%o\n", + sectcurr, oldcrc); + } + /* make sure eot really is eot and not just mixmash */ +#ifdef NFGVMIN + else if (firstch==EOT && readline(1)==TIMEOUT) + return WCEOT; +#else + else if (firstch==EOT && Lleft==0) + return WCEOT; +#endif + else if (firstch==CAN) { + if (Lastrx==CAN) { + log("Sender CANcelled\n"); + return ERROR; + } else { + Lastrx=CAN; + continue; + } + } + else if (firstch==TIMEOUT) { + if (Firstsec) + goto humbug; +bilge: + log( "Timeout\n"); + } + else + log( "Got 0%o sector header\n", firstch); + +humbug: + Lastrx=0; + while(readline(1)!=TIMEOUT) + ; + if (Firstsec) { + sendline(Crcflg?WANTCRC:NAK); + Lleft=0; /* Do read next time ... */ + } else { + maxtime=40; sendline(NAK); + Lleft=0; /* Do read next time ... */ + } + } + /* try to stop the bubble machine. */ + canit(); + return ERROR; +} + +/* + * This version of readline is reasoably well suited for + * reading many characters. + * (except, currently, for the Regulus version!) + * + * timeout is in tenths of seconds + */ +int readline(int timeout) +{ + static char *cdq; /* pointer for removing chars from linbuf */ + static char data_buffer[8]; + if (--Lleft >= 0) + { + return (*cdq++ & Wcsmask); + } + while (1) + { + Lleft = zread(shell->device, 0, data_buffer, 1); + if (Lleft) + { + Lleft = Lleft; + cdq = &data_buffer[0]; + break; + } + } + + if (Lleft < 1) + return TIMEOUT; + --Lleft; + return (*cdq++ & Wcsmask); +} + + + +/* + * Purge the modem input queue of all characters + */ +int purgeline(void) +{ + + Lleft = 0; +#ifdef USG + ioctl(iofd, TCFLSH, 0); +#else + lseek(iofd, 0L, 2); +#endif + return 0; +} + +/* + * Update CRC CRC-16 used by XMODEM/CRC, YMODEM, and ZMODEM. + * Note: Final result must be masked with 0xFFFF before testing + * More efficient table driven routines exist. + */ +unsigned short int +updcrc(int c, int crc) +{ + int count; + + for (count=8; --count>=0;) { + if (crc & 0x8000) { + crc <<= 1; + crc += (((c<<=1) & 0400) != 0); + crc ^= 0x1021; + } + else { + crc <<= 1; + crc += (((c<<=1) & 0400) != 0); + } + } + return crc; +} + +/* + * Process incoming file information header + */ +int procheader(char *name) +{ + char *openmode, *ptr; + unsigned char i; + char fname[100]; + /* set default parameters */ + openmode = "w"; Thisbinary=Rxbinary; + + /* + * Process ZMODEM remote file management requests + */ + if (zconv == ZCNL) /* Remote ASCII override */ + Thisbinary = 0; + if (zconv == ZCBIN) /* Remote Binary override */ + ++Thisbinary; + else if (zmanag == ZMAPND) + openmode = "a"; + openmode = openmode; + Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L; + for(i=0;i<100;i++) fname[i] = 0; + for (i=1,ptr=name;i=0; ) + write(fout,p++,1); + } + else { + if (Eofseen) + return OK; + for (p=buf; --n>=0; ++p ) { + if ( *p == '\r') + continue; + if (*p == CPMEOF) { + Eofseen=TRUE; return OK; + } + write(fout,p,1); + } + } + return OK; +} + +/* + * Send a character to modem. Small is beautiful. + */ +int sendline(int c) +{ + zwrite(c); + return 0; +} + +int xsendline(int c) +{ + sendline(c); + return 0; +} + +int flushmo(void) +{ + return 0; +} + + + + +/* + * substr(string, token) searches for token in string s + * returns pointer to token within string if found, NULL otherwise + */ +char * +substr(char *s, char *t) +{ + register char *ss,*tt; + /* search for first char of token */ + for (ss=s; *s; s++) + if (*s == *t) + /* compare token with substring */ + for (ss=s,tt=t; ;) { + if (*tt == 0) + return s; + if (*ss++ != *tt++) + break; + } + return NULL; +} + +/* + * Log an error + */ +/*VARARGS1*/ +int log(const char *s,...) +{ + return 0; +} + +/* send cancel string to get the other end to shut up */ +int canit(void) +{ /* + static char canistr[] = { + ZPAD,ZPAD,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0 + }; + */ + //printf(canistr); + Lleft=0; /* Do read next time ... */ + //fflush(stdout); + return 0; +} + + +/* + * Return 1 iff stdout and stderr are different devices + * indicating this program operating with a modem on a + * different line + */ +int fromcu(void) +{ + struct stat a, b; + fstat(1, &a); + fstat(2, &b); + //return (a.st_rdev != b.st_rdev); + return 0; +} + +int report(int sct) +{ + //if (Verbose>1) + // rt_kprintf(stderr,"%03d%c",sct,sct%10? ' ' : '\r'); + return 0; +} + +/* + * If called as [-][dir/../]vrzCOMMAND set Verbose to 1 + * If called as [-][dir/../]rzCOMMAND set the pipe flag + * If called as rb use YMODEM protocol + */ +int chkinvok(char *s) +{ + register char *p; + + p = s; + while (*p == '-') + s = ++p; + while (*p) + if (*p++ == '/') + s = p; + if (*s == 'v') { + Verbose=1; ++s; + } + Progname = s; + if (s[0]=='r' && s[1]=='b') + Nozmodem = TRUE; + if (s[2] && s[0]=='r' && s[1]=='b') + Topipe=TRUE; + if (s[2] && s[0]=='r' && s[1]=='z') + Topipe=TRUE; + return 0; +} + +/* + * Totalitarian Communist pathname processing + */ +int checkpath(char *name) +{ +// if (Restricted) { + // if (fopen(name, "r") != NULL) { + // canit(); + //rt_kprintf(stderr, "\r\nrz: %s exists\n", name); + // bibi(); + // } + /* restrict pathnames to current tree or uucppublic */ + // if ( substr(name, "../") + // || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) { + // canit(); + //rt_kprintf(stderr,"\r\nrz:\tSecurity Violation\r\n"); + // bibi(); + // } +// } + return 0; +} + +/* + * Initialize for Zmodem receive attempt, try to activate Zmodem sender + * Handles ZSINIT frame + * Return ZFILE if Zmodem filename received, -1 on error, + * ZCOMPL if transaction finished, else 0 + */ +int tryz(void) +{ + int n; + int cmdzack1flg; + + if (Nozmodem) /* Check for "rb" program name */ + return 0; + Rxtimeout = 100; + + + for (n=5; --n>=0; ) { + /* Set buffer length (0) and capability flags */ + stohdr(0L); + Txhdr[ZF0] = CANFDX|CANOVIO|CANBRK; + zshhdr(Badclose?ZFERR:ZRINIT, Txhdr); +again: + switch (zgethdr(Rxhdr, 0)) { + case ZRQINIT: + continue; + case ZEOF: + continue; + case TIMEOUT: + continue; + case ZFILE: + zconv = Rxhdr[ZF0]; + zmanag = Rxhdr[ZF1]; + ztrans = Rxhdr[ZF2]; + Badclose = FALSE; + if (zrbdata(secbuf, KSIZE) == GOTCRCW) + return ZFILE; + zshhdr(ZNAK, Txhdr); + case ZSINIT: + if (zrbdata(Attn, ZATTNLEN) == GOTCRCW) { + zshhdr(ZACK, Txhdr); + goto again; + } + zshhdr(ZNAK, Txhdr); + continue; + case ZFREECNT: + stohdr(getfree()); + zshhdr(ZACK, Txhdr); + goto again; + case ZCOMMAND: + cmdzack1flg = Rxhdr[ZF0]; + if (zrbdata(secbuf, KSIZE) == GOTCRCW) { + if (cmdzack1flg & ZCACK1) + stohdr(0L); + else + stohdr((long)sys2(secbuf)); + purgeline(); /* dump impatient questions */ + do { + zshhdr(ZCOMPL, Txhdr); + } + while (++errors<10 && zgethdr(Rxhdr,1) != ZFIN); + ackbibi(); + if (cmdzack1flg & ZCACK1) + exec2(secbuf); + return ZCOMPL; + } + zshhdr(ZNAK, Txhdr); goto again; + case ZCOMPL: + goto again; + default: + continue; + case ZFIN: + ackbibi(); return ZCOMPL; + case ZCAN: + return ERROR; + } + } + return 0; +} + +/* + * Receive 1 or more files with ZMODEM protocol + */ +int rzfiles(void) +{ + int c; + + for (;;) { + switch (c = rzfile()) { + case ZEOF: + case ZSKIP: + switch (tryz()) { + case ZCOMPL: + return OK; + default: + return ERROR; + case ZFILE: + break; + } + continue; + default: + return c; + case ERROR: + return ERROR; + } + } +} + +/* + * Receive a file with ZMODEM protocol + * Assumes file name frame is in secbuf + */ +int rzfile(void) +{ + int c, n; + long int rxbytes; + + Eofseen=FALSE; + if (procheader(secbuf) == ERROR) { + zshhdr(ZSKIP, Txhdr); + return ZSKIP; + } + + n = 10; rxbytes = 0l; + + for (;;) { + stohdr(rxbytes); + zshhdr(ZRPOS, Txhdr); +nxthdr: + switch (c = zgethdr(Rxhdr, 0)) { + default: + vfile("rzfile: zgethdr returned %d", c); + return ERROR; + case ZNAK: + case TIMEOUT: + if ( --n < 0) { + vfile("rzfile: zgethdr returned %d", c); + return ERROR; + } + case ZFILE: + continue; + case ZEOF: + if (rclhdr(Rxhdr) != rxbytes) { + continue; + } + if (closeit()) { + Badclose = TRUE; + vfile("rzfile: closeit returned <> 0"); + return ERROR; + } + vfile("rzfile: normal EOF"); + return c; + case ERROR: /* Too much garbage in header search error */ + if ( --n < 0) { + vfile("rzfile: zgethdr returned %d", c); + return ERROR; + } + zmputs(Attn); + continue; + case ZDATA: + n = 10; + if (rclhdr(Rxhdr) != rxbytes) { + zmputs(Attn); + continue; + } +moredata: + switch (c = zrbdata(secbuf, KSIZE)) { + case ZCAN: + vfile("rzfile: zgethdr returned %d", c); + return ERROR; + case ERROR: /* CRC error */ + if ( --n < 0) { + vfile("rzfile: zgethdr returned %d", c); + return ERROR; + } + zmputs(Attn); + continue; + case TIMEOUT: + if ( --n < 0) { + vfile("rzfile: zgethdr returned %d", c); + return ERROR; + } + continue; + case GOTCRCW: + putsec(secbuf, Rxcount); + rxbytes += Rxcount; + stohdr(rxbytes); + zshhdr(ZACK, Txhdr); + goto nxthdr; + case GOTCRCQ: + putsec(secbuf, Rxcount); + rxbytes += Rxcount; + stohdr(rxbytes); + zshhdr(ZACK, Txhdr); + goto moredata; + case GOTCRCG: + putsec(secbuf, Rxcount); + rxbytes += Rxcount; + goto moredata; + case GOTCRCE: + putsec(secbuf, Rxcount); + rxbytes += Rxcount; + goto nxthdr; + } + } + } +} + +/* + * Send a string to the modem, processing for \336 (sleep 1 sec) + * and \335 (break signal) + */ +int zmputs(char *s) +{ + int c; + + while (*s) { + switch (c = *s++) { + case '\336': + //sleep(1); + continue; + case '\335': + sendbrk(); continue; + default: + sendline(c); + } + } + return 0; +} + +/* + * Close the receive dataset, return OK or ERROR + */ +int closeit(void) +{ + if (Topipe) { + if (close(fout)) { + return ERROR; + } + return OK; + } + if (close(fout)==ERROR) { + //rt_kprintf(stderr, "file close ERROR\n"); + return ERROR; + } +// if (Modtime) { +// timep[0] = time(NULL); + // timep[1] = Modtime; + // utime(Pathname, timep); + //} + //if (Filemode) + //chmod(Pathname, (07777 & Filemode)); + return OK; +} + +/* + * Ack a ZFIN packet, let byegones be byegones + */ +int ackbibi(void) +{ + int n; + + vfile("ackbibi:"); + Readnum = 1; + stohdr(0L); + for (n=4; --n>=0; ) { + zshhdr(ZFIN, Txhdr); + for (;;) { + switch (readline(100)) { + case 'O': + readline(1); /* Discard 2nd 'O' */ + /* ***** FALL THRU TO ***** */ + case TIMEOUT: + vfile("ackbibi complete"); + return 0; + default: + break; + } + } + } + return 0; +} + +/* + * Local console output simulation + */ +int bttyout(int c) +{ + //if (Verbose || fromcu) + //putc(c, stderr); + return 0; +} + +/* + * Strip leading ! if present, do shell escape. + */ +int sys2(char *s) +{ + if (*s == '!') + ++s; + return 0; +} +/* + * Strip leading ! if present, do exec. + */ +int exec2(char *s) +{ + if (*s == '!') + ++s; + mode(0); + return 0; +} diff --git a/components/utilities/ZMODEM/RZ.H b/components/utilities/ZMODEM/RZ.H new file mode 100644 index 0000000000..8a4f237114 --- /dev/null +++ b/components/utilities/ZMODEM/RZ.H @@ -0,0 +1,77 @@ +#ifndef __RZ_H__ +#define __RZ_H__ + +#include "zmodem.h" + + +unsigned short int updcrc(int c, unsigned int crc); +void zmputs(char *s); +int closeit(void); +int sys2(char *s); +int exec2(char *s); +int rzfile(void); +void ackbibi(void); +unsigned int IsAnyLower(char *s); +void usage(void); +static int wcrx(void); +char *substr(char *s, char *t); + +void alrm(void); +void bibi(int n); +int zreceive_main(void); +void usage(void); +static int wcreceive(unsigned int argc, char **argp); +static int wcrxpn(char *rpn); +static int wcgetsec(char *rxbuf, int maxtime); +int readline(int timeout); +unsigned short int updcrc(int c, unsigned int crc); +int procheader(char *name); +int purgeline(void); +int putsec(char *buf, int n); +int readline(int timeout); +unsigned short int updcrc(int c, unsigned int crc); + +int bttyout(int c); +int sys2(char *s); +int exec2(char *s); +void sendline(char c); +void xsendline(char c); +void canit(void); +int tryz(void); +int rzfiles(void); + + +extern int Verbose; +extern int iofd; /* File descriptor for ioctls & reads */ +extern int Zmodem; /* ZMODEM protocol requested */ +extern int Nozmodem; /* If invoked as "rb" */ +/* Ward Christensen / CP/M parameters - Don't change these! */ +#define ENQ 005 +#define CAN ('X'&037) +//#define XOFF ('s'&037) +//#define XON ('q'&037) +#define SOH 1 +#define STX 2 +#define EOT 4 +#define ACK 6 +#define NAK 025 +#define CPMEOF 032 +#define WANTCRC 0103 /* send C not NAK to get crc not checksum */ +#define TIMEOUT (-2) +#define ERRORMAX 5 +#define RETRYMAX 5 +#define WCEOT (-10) +#define SECSIZ 128 /* cp/m's Magic Number record size */ +#define PATHLEN 257 /* ready for 4.2 bsd ? */ +#define KSIZE 1024 /* record size with k option */ +#define UNIXFILE 0x8000 /* happens to the the S_IFREG file mask bit for stat */ +/**************************zm.c **************************/ + + + + + + + + +#endif diff --git a/components/utilities/ZMODEM/SZ.1 b/components/utilities/ZMODEM/SZ.1 new file mode 100644 index 0000000000..e5cd56029a --- /dev/null +++ b/components/utilities/ZMODEM/SZ.1 @@ -0,0 +1,336 @@ +'\" Revision Level +'\" Last Delta 5-19-86 +.TH SZ 1 OMEN +.SH NAME +sz \- XMODEM, YMODEM, ZMODEM Batch file Send +.SH SYNOPSIS +sz +.RB [\- +1adfknqTuvy ] +.I file ... +.br +sz -X +.RB [\- 1kquv ] +.I file +.br +sz +.RB [\- 1qv ] +.B "-c COMMAND" +.br +sz +.RB [\- 1qv ] +.B "-i COMMAND" +.SH DESCRIPTION +.B Sz +uses the ZMODEM, YMODEM or XMODEM error correcting protocol to send +one or more files over a serial port to a variety of programs running under +PC-DOS, CP/M, Unix, VMS, and other operating systems. + + +The first form of +.B sz +sends one or more files with ZMODEM or YMODEM batch protocol. +Normally, only the file name part of the pathname is transmitted. +On +.SM Unix +systems, additional information about the file is transmitted. +If the receiving program uses this information, +the transmitted file length controls the exact number of bytes written to +the output dataset, +and the modify time and file mode +are set accordingly. + +Output from another program may be piped to +.B sz +for transmission by specifying the +.B -1 +option and denoting standard input by "-": +.ce +ps -ef | sz - +The program output is transmitted with the filename sPID.sz +where PID is the process ID of the +.B sz +program. +If the environment variable +.B ONAME +is set, that is used instead. +In this case, the Unix command: +.ce +ONAME=con ps -ef|sz -ay - +will send a "file" to the PC-DOS console display. +The +.B -y +bypasses the receiver\'s checking of the output filename. +The +.B -a +causes the receiver to convert Unix newlines to PC-DOS carriage returns +and linefeeds. + +Unix +.B sz +supports +.B YMODEM-g +with "cbreak" tty mode, XON/XOFF flow control, +and the interrupt character set to CAN. +.B YMODEM-g +(Professional-YAM +.B g +option) +increases throughput over error free channels +(direct connection, X.PC, etc.) +by not acknowledging each transmitted sector. + + +The second form of +.B sz +uses the +.B -X +flag to send a single +.I file +with +.B XMODEM +protocol. +The user must supply the file name to both sending and receiving programs. + +Iff +.B sz +is invoked with $SHELL set and iff that variable contains the +string +.I "rsh" +or +.I "rksh" +(restricted shell), sz operates in restricted mode. +Restricted mode restricts pathnames to the current directory and +PUBDIR (usually /usr/spool/uucppublic) and/or subdirectories +thereof. + + +The third form sends a single COMMAND to the receiver for execution. +.B Sz +exits with the COMMAND return value. +If COMMAND includes spaces or characters special to the shell, +it must be quoted. + +The fourth form sends a single COMMAND to the receiver for execution. +.B Sz +exits as soon as the receiver has received the command, before it is executed. + + +If sz is invoked with stdout and stderr to different datasets, +Verbose is set to 2, causing frame by frame progress reports +to stderr. +This may be disabled with the +.B q +option. +.PP +The meanings of the available options are: +.PP +.PD 0 +.TP +.B + +Force the receiver to append transmitted data to an existing file +(ZMODEM only). +.TP +.B 1 +Use file descriptor 1 for ioctls and reads (Unix only). +By default, file descriptor 0 is used. +This option allows +.B sz +to be used with the +.I cu +~$ +command. +.TP +.B a +Convert NL characters in the transmitted file to CR/LF. +This is done by the sender for XMODEM and YMODEM, by the receiver +for ZMODEM. +.TP +.B "c COMMAND" +Send COMMAND to the receiver for execution, return with COMMAND\'s exit status. +.TP +.B "C N" +Make N attempts at ten second intervals +to read COMMAND\'s exit status before exiting. +.TP +.B d +Change all instances of "." to "/" in the transmitted pathname. +Thus, C.omenB0000 (which is unacceptable to MSDOS or CP/M) +is transmitted as C/omenB0000. +If the resultant filename has more than 8 characters in the stem, +a "." in inserted to allow a total of eleven. +.TP +.B f +Send Full pathname. +Normally directory prefixes are stripped from the transmitted +filename. +.TP +.B "i COMMAND" +Send COMMAND to the receiver for execution, return Immediately. +.TP +.B k +Send files using YMODEM 1024 byte blocks +rather than the default 128 byte blocks. +1024 byte packets speed file transfers at high bit rates. +(ZMODEM streams the data for the best possible throughput.) +.TP +.B n +Instruct ZMODEM receiver to skip files if the length and modification times +of the source file and the file on the destination system are equal. +.TP +.B N +Instruct ZMODEM receiver to skip files if the length and CRC\'s +of the source file and the file on the destination system are equal. +.TP +.B q +Quiet suppresses verbosity. +.TP +.B r +Resume interrupted file transfer. +If the source file is longer than the destination file, +the transfer commences at the offset in the source file that equals +the length of the destination file. +.TP +.B u +Unlink the file after successful transmission. +.TP +.B v +Verbose +causes a list of file +names to be appended to +/tmp/szlog . +More v's generate more output. +.TP +.B X +Send a single file with +.B XMODEM +protocol. +.TP +.B y +Force a ZMODEM receiving program to overwrite any existing file +with the same name. +.PD +.SH EXAMPLES +.ne 7 +.B "ZMODEM File Transfer" +.br +.B "$ sz -a *.c" +.br +This single command transfers all .c files in the current Unix directory +with conversion +.RB ( -a ) +to PC-DOS end of line conventions. +With ZMODEM AutoDownload enabled, Professional-YAM automatically recieves +the files after performing a security challenge. + +.B "ZMODEM Command Download" +.br + cpszall:all + sz -c "c:;cd /yam/dist" + sz -ya $(YD)/*.me + sz -yqb y*.exe + sz -c "cd /yam" + sz -i "!insms" +.br +This Makefile fragment uses +.B sz +to issue commands to Professional-YAM to change current disk and directory. +Next, +.B sz +transfers the +.I .me +files from the $YD directory, commanding the receiver to overwrite the old files +and to convert from Unix end of line conventions to PC-DOS conventions. +The third line transfers some +.I .exe +files. +The fourth and fifth lines command Pro-YAM to +change directory and execute a PC-DOS batch file +.I insms . +Since the batch file takes considerable time, the +.B "-i" +form is used to allow +.B sz +to exit immediately. + +.B "XMODEM File Transfer" +.br +$ +.B "sz -Xa foo.c" +.br +.B "ESC" +.br +.B "rx foo.c" +.br +The above three commands transfer a single file +from Unix to a PC and Crosstalk XVI 3.6, +translating Unix newlines to DOS CR/LF. + +.SH SEE ALSO +rz(omen), +ZMODEM.DOC, +YMODEM.DOC, +Professional-YAM manual, +IMP(CP/M), +cu(1), +sq(omen), +todos(omen), +tocpm(omen), +tomac(omen), +yam(omen) + +Compile time options required for various operating systems are described in +the source file. +.SH "VMS VERSION" +The VMS version does not transmit the file date. +The VMS version calculates the file length by reading the file +and counting the bytes. + +The VMS version does not support YMODEM-g or ZMODEM. + +When VMS is lightly loaded, the response time may be too quick for MODEM7 +unless the MODEM7 +.B "q" +modifier is used. + +The VMS C standard i/o package and RMS sometimes interact to modify +file contents unexpectedly. +.SH FILES +sz.c, rbsb.c, zm.c, zmodem.h source files + +/tmp/szlog stores debugging output (sz -vv) +.SH "TESTING FEATURE" +The command "sz -T file" +exercises the +.B Attn +sequence error recovery by commanding +errors with unterminated packets. +The receiving program should complain five times about +binary data packets being too long. +Each time +.B sz +is interrupted, +it should send a ZDATA header followed by another defective packet. +If the receiver does not detect five long data packets, +the +.B Attn +sequence is not interrupting the sender, and the +.B Myattn +string in +.B sz.c +must be modified. + +After 5 packets, +.B sz +stops the "transfer" and +prints the total number of characters "sent" (Tcount). +The difference between Tcount and 5120 represents the number of characters +stored in various buffers when the Attn sequence is generated. +.SH BUGS +XMODEM transfers add up to 127 spurious bytes per file. + +Circular buffering and a ZMODEM sliding window should be used +when input is from pipes instead of acknowledging frames each 1024 bytes. +.B Sz +should check for the presence of at least one accessible file before +getting hot and bothered. +The test mode leaves a zero length file on the receiving system. diff --git a/components/utilities/ZMODEM/SZ.C b/components/utilities/ZMODEM/SZ.C new file mode 100644 index 0000000000..f4aaaae345 --- /dev/null +++ b/components/utilities/ZMODEM/SZ.C @@ -0,0 +1,1168 @@ +#define VERSION "sz 1.03 05-18-86" +#define PUBDIR "/usr/spool/uucppublic" + +/*% cc -O -K sz.c -o sz; size sz + + * sz.c By Chuck Forsberg + * + * cc -O sz.c -o sz USG (SYS III/V) Unix + * cc -O -DV7 sz.c -o sz Unix Version 7, 2.8 - 4.3 BSD + * + * ******* Some systems (Venix, Coherent, Regulus) do not ******* + * ******* support tty raw mode read(2) identically to ******* + * ******* Unix. ONEREAD must be defined to force one ******* + * ******* character reads for these systems. ******* + * + * A program for Unix to send files and commands to computers running + * Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM. + * + * Sz uses buffered I/O to greatly reduce CPU time compared to UMODEM. + * + * USG UNIX (3.0) ioctl conventions courtesy Jeff Martin + */ + +/* + * Attention string to be executed by receiver to interrupt streaming data + * when an error is detected. A pause (0336) may be needed before the + * ^C (03) or after it. + */ +char Myattn[] = { 03, 0336, 0 }; + +unsigned updcrc(); +char *substr(), *getenv(); + +#define LOGFILE "/tmp/szlog" +#define zperr vfile + +/* +#include +#include +#include +#include +*/ +#include "rtthread.h" +#include "finsh.h" +#include "shell.h" +#include"rtdef.h" +#include +#include +#include +#include "zmodem.h" + +#define PATHLEN 256 +#define OK 0 +#define FALSE 0 +#define TRUE 1 +#define ERROR (-1) + +#define HOWMANY 2 +int Zmodem=0; /* ZMODEM protocol requested */ +unsigned Baudrate; +#include "rbsb.c" /* most of the system dependent stuff here */ + +int in; + +/* Ward Christensen / CP/M parameters - Don't change these! */ +#define ENQ 005 +#define CAN ('X'&037) +#define XOFF ('s'&037) +#define XON ('q'&037) +#define SOH 1 +#define STX 2 +#define EOT 4 +#define ACK 6 +#define NAK 025 +#define CPMEOF 032 +#define WANTCRC 0103 /* send C not NAK to get crc not checksum */ +#define WANTG 0107 /* Send G not NAK to get nonstop batch xmsn */ +#define TIMEOUT (-2) +#define RETRYMAX 10 +#define SECSIZ 128 /* cp/m's Magic Number record size */ +#define KSIZE 1024 + +char Lastrx; +char Crcflg; +int Wcsmask=0377; +int Verbose=0; +int Modem=0; /* MODEM - don't send pathnames */ +int Restricted=0; /* restricted; no /.. or ../ in filenames */ +int Quiet=0; /* overrides logic that would otherwise set verbose */ +int Ascii=0; /* Add CR's for brain damaged programs */ +int Fullname=0; /* transmit full pathname */ +int Unlinkafter=0; /* Unlink file after it is sent */ +int Dottoslash=0; /* Change foo.bar.baz to foo/bar/baz */ +int firstsec; +int errcnt=0; /* number of files unreadable */ +int blklen=SECSIZ; /* length of transmitted records */ +int Optiong; /* Let it rip no wait for sector ACK's */ +int Noeofseen; +int Totsecs; /* total number of sectors this file */ +char txbuf[KSIZE]; +int Filcnt=0; /* count of number of files opened */ +int Lfseen=0; +unsigned Rxbuflen = 16384; /* Receiver's max buffer length */ +int Rxflags = 0; +char Lzconv; /* Local ZMODEM file conversion request */ +char Lzmanag; /* Local ZMODEM file management request */ +char Lztrans; +char zconv; /* ZMODEM file conversion request */ +char zmanag; /* ZMODEM file management request */ +char ztrans; /* ZMODEM file transport request */ +int Command; /* Send a command, then exit. */ +char *Cmdstr; /* Pointer to the command string */ +int Cmdtries = 11; +int Cmdack1; /* Rx ACKs command, then do it */ +int Exitcode; +int Testattn; /* Force receiver to send Attn, etc with qbf. */ +char *qbf="The quick brown fox jumped over the lazy dog's back 1234567890\r\n"; + + +//jmp_buf tohere; /* For the interrupt on RX timeout */ +//jmp_buf intrjmp; /* For the interrupt on RX CAN */ + +/* called by signal interrupt or terminate to clean things up */ +bibi(n) +{ + canit(); + //fflush(stdout); + mode(0); + //rt_kprintf(stderr, "sz: caught signal %d; exiting\n", n); + //if (n == SIGQUIT) + // abort(); + //exit(128+n); +} +/* Called when Zmodem gets an interrupt (^X) */ +onintr() +{ + //signal(SIGINT, SIG_IGN); + //longjmp(intrjmp, -1); +} + + +//#define sendline(c) putchar(c & Wcsmask) + +//#define xsendline(c) putchar(c) +int sendline (int c) +{ + c = c&Wcsmask; + zwrite(c); + +} +int xsendline(int c) +{ + zwrite(c); +} + + +flushmo() +{ + //fflush(stdout); +} + +#include "zm.c" + +zsmain(argc, argv) +char *argv[]; +{ + register char *cp; + register npats; + int agcnt; char **agcv; + char **patts; + static char xXbuf[BUFSIZ]; + + //if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rsh"))) + // Restricted=TRUE; + + Rxtimeout = 600; + npats=0; + /* + if (argc<2) + usage(); + //setbuf(stdout, xXbuf); + while (--argc) { + cp = *++argv; + if (*cp++ == '-' && *cp) { + while ( *cp) { + switch(*cp++) { + case '+': + Lzmanag = ZMAPND; break; + case '1': + iofd = 1; break; + case '7': + Wcsmask=0177; break; + case 'a': + Lzconv = ZCNL; + Ascii = TRUE; break; + case 'b': + Lzconv = ZCBIN; break; + case 'C': + if (--argc < 1) { + usage(); + } + Cmdtries = atoi(*++argv); + break; + case 'i': + Cmdack1 = ZCACK1; + //* **** FALL THROUGH TO **** + case 'c': + if (--argc != 1) { + usage(); + } + Command = TRUE; + Cmdstr = *++argv; + break; + case 'd': + ++Dottoslash; + //* **** FALL THROUGH TO **** * + case 'f': + Fullname=TRUE; break; + case 'k': + blklen=KSIZE; break; + case 'N': + Lzmanag = ZMCRC; break; + case 'n': + Lzmanag = ZMNEW; break; + case 'r': + Lzconv = ZCRESUM; + case 'q': + Quiet=TRUE; Verbose=0; break; + case 'T': + Testattn = TRUE; break; + case 'u': + ++Unlinkafter; break; + case 'v': + ++Verbose; break; + case 'X': + ++Modem; break; + case 'y': + Lzmanag = ZMCLOB; break; + default: + usage(); + } + } + } + else if ( !npats && argc>0) { + if (argv[0][0]) { + npats=argc; + patts=argv; + if ( !strcmp(*patts, "-")) + iofd = 1; + } + } + } + if (npats < 1 && !Command) + usage(); + if (Verbose) { + if (freopen(LOGFILE, "a", stderr)==NULL) { + printf("Can't open log file %s\n",LOGFILE); + exit(0200); + } + setbuf(stderr, NULL); + } + if (fromcu() && !Quiet) { + if (Verbose == 0) + Verbose = 2; + } + + mode(1); + +// if (signal(SIGINT, bibi) == SIG_IGN) { +// signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN); +// } +// else { + // signal(SIGINT, bibi); signal(SIGKILL, bibi); +// signal(SIGQUIT, bibi); +// } + + if ( !Modem) { + if (!Command) { + printf("rz\r"); fflush(stdout); + } + if (!Command && !Quiet && Verbose != 1) { + rt_kprintf(stderr, "sz: %d file%s requested:\r\n", + npats, npats>1?"s":""); + for ( agcnt=npats, agcv=patts; --agcnt>=0; ) { + rt_kprintf(stderr, "%s ", *agcv++); + } + rt_kprintf(stderr, "\r\n"); + printf("\r\n\bSending in Batch Mode\r\n"); + } + stohdr(0L); + if (Command) + Txhdr[ZF0] = ZCOMMAND; + zshhdr(ZRQINIT, Txhdr); + } + fflush(stdout); + */ + if (Command) { + if (getzrxinit()) { + Exitcode=0200; canit(); + } + else if (zsendcmd(Cmdstr, 1+strlen(Cmdstr))) { + Exitcode=0200; canit(); + } + } else if (wcsend(npats, patts)==ERROR) { + Exitcode=0200; + canit(); + } + //fflush(stdout); + //mode(0); + //exit((errcnt != 0) | Exitcode); + /*NOTREACHED*/ +} + +wcsend(argc, argp) +char *argp[]; +{ + register n; + + Crcflg=FALSE; + firstsec=TRUE; + //for (n=0; n>7); + //} + //rt_kprintf(stderr, "Give your local XMODEM receive command now.\r\n"); + return OK; + } + logent("\r\nAwaiting pathname nak for %s\r\n", *name?name:""); + if ( !Zmodem) + if (getnak()) + return ERROR; + + q = (char *) 0; + if (Dottoslash) { /* change . to . */ + for (p=name; *p; ++p) { + if (*p == '/') + q = p; + else if (*p == '.') + *(q=p) = '/'; + } + if (q && strlen(++q) > 8) { /* If name>8 chars */ + q += 8; /* make it .ext */ + strcpy(name2, q); /* save excess of name */ + *q = '.'; + strcpy(++q, name2); /* add it back */ + } + } + + for (p=name, q=txbuf ; *p; ) + if ((*q++ = *p++) == '/' && !Fullname) + q = txbuf; + *q++ = 0; + p=q; + while (q < (txbuf + KSIZE)) + *q++ = 0; + //if (!Ascii && (in!=stdin) && *name && fstat(fileno(in), &f)!= -1) + //sprintf(p, "%lu %lo %o", f.st_size, f.st_mtime, f.st_mode); + fstat(in,&f); + /* force 1k blocks if name won't fit in 128 byte block */ + if (txbuf[125]) + blklen=KSIZE; + else { /* A little goodie for IMP/KMD */ + if (Zmodem) + blklen = SECSIZ; + txbuf[127] = f.st_size >>7; + txbuf[126] = f.st_size >>15; + } + if (Zmodem) + return zsendfile(txbuf, 1+strlen(p)+(p-txbuf)); + if (wcputsec(txbuf, 0, SECSIZ)==ERROR) + return ERROR; + return OK; +} + +getnak() +{ + register firstch; + + Lastrx = 0; + for (;;) { + switch (firstch = readock(800,1)) { + case ZPAD: + if (getzrxinit()) + return ERROR; + Ascii = 0; + return FALSE; + case TIMEOUT: + logent("Timeout on pathname\n"); + return TRUE; + case WANTG: + mode(2); /* Set cbreak, XON/XOFF, etc. */ + Optiong = TRUE; + blklen=KSIZE; + case WANTCRC: + Crcflg = TRUE; + case NAK: + return FALSE; + case CAN: + if (Lastrx == CAN) + return TRUE; + default: + break; + } + Lastrx = firstch; + } +} + + +wctx() +{ + register int sectnum, attempts, firstch; + + firstsec=TRUE; + + while ((firstch=readock(400, 2))!=NAK && firstch != WANTCRC + && firstch != WANTG && firstch!=TIMEOUT && firstch!=CAN) + ; + if (firstch==CAN) { + logent("Receiver CANcelled\n"); + return ERROR; + } + if (firstch==WANTCRC) + Crcflg=TRUE; + if (firstch==WANTG) + Crcflg=TRUE; + sectnum=1; + while (filbuf(txbuf, blklen)) { + if (wcputsec(txbuf, sectnum, blklen)==ERROR) { + return ERROR; + } else + sectnum++; + } + //if (Verbose>1) + // rt_kprintf(stderr, " Closing "); + close(in); + attempts=0; + do { + logent(" EOT "); + purgeline(); + sendline(EOT); + //fflush(stdout); + ++attempts; + } + while ((firstch=(readock(100, 1)) != ACK) && attempts < RETRYMAX); + if (attempts == RETRYMAX) { + logent("No ACK on EOT\n"); + return ERROR; + } + else + return OK; +} + +wcputsec(buf, sectnum, cseclen) +char *buf; +int sectnum; +int cseclen; /* data length of this sector to send */ +{ + register checksum, wcj; + register char *cp; + unsigned oldcrc; + int firstch; + int attempts; + + firstch=0; /* part of logic to detect CAN CAN */ + + //if (Verbose>1) + // rt_kprintf(stderr, "\rSector %3d %2dk ", Totsecs, Totsecs/8 ); + for (attempts=0; attempts <= RETRYMAX; attempts++) { + Lastrx= firstch; + sendline(cseclen==KSIZE?STX:SOH); + sendline(sectnum); + sendline(-sectnum -1); + oldcrc=checksum=0; + for (wcj=cseclen,cp=buf; --wcj>=0; ) { + sendline(*cp); + oldcrc=updcrc(*cp, oldcrc); + checksum += *cp++; + } + if (Crcflg) { + oldcrc=updcrc(0,updcrc(0,oldcrc)); + sendline((int)oldcrc>>8); + sendline((int)oldcrc); + } + else + sendline(checksum); + + if (Optiong) { + firstsec = FALSE; return OK; + } + firstch = readock(400, (Noeofseen&§num) ? 2:1); +gotnak: + switch (firstch) { + case CAN: + if(Lastrx == CAN) { +cancan: + logent("Cancelled\n"); return ERROR; + } + break; + case TIMEOUT: + logent("Timeout on sector ACK\n"); continue; + case WANTCRC: + if (firstsec) + Crcflg = TRUE; + case NAK: + logent("NAK on sector\n"); continue; + case ACK: + firstsec=FALSE; + Totsecs += (cseclen>>7); + return OK; + case ERROR: + logent("Got burst for sector ACK\n"); break; + default: + logent("Got %02x for sector ACK\n", firstch); break; + } + for (;;) { + Lastrx = firstch; + if ((firstch = readock(400, 2)) == TIMEOUT) + break; + if (firstch == NAK || firstch == WANTCRC) + goto gotnak; + if (firstch == CAN && Lastrx == CAN) + goto cancan; + } + } + logent("Retry Count Exceeded\n"); + return ERROR; +} + +/* fill buf with count chars padding with ^Z for CPM */ +filbuf(buf, count) +register char *buf; +{ + register c, m; + + if ( !Ascii) { + m = read(in, buf, count); + if (m <= 0) + return 0; + while (m < count) + buf[m++] = 032; + return count; + } + m=count; + if (Lfseen) { + *buf++ = 012; --m; Lfseen = 0; + } + ///////////////////////////////////////////////////////////////////////////////////// + /* + while ((c=getc(in))!=EOF) { + if (c == 012) { + *buf++ = 015; + if (--m == 0) { + Lfseen = TRUE; break; + } + } + *buf++ =c; + if (--m == 0) + break; + } + */ + if (m==count) + return 0; + else + while (--m>=0) + *buf++ = CPMEOF; + return count; +} +/* fill buf with count chars */ +zfilbuf(buf, count) +register char *buf; +{ //int read(int fd, void *buf, size_t len) + int c, m; + int res; + + m=count; + res = 0; + while (1) { + res = read(in,&c,1); + if (res == 0) break; + *buf++ =c; + res = 0; + if (--m == 0) + break; + } + return (count - m); +} + +/* VARARGS1 */ +vfile(f, a, b, c) +register char *f; +{ +// if (Verbose > 1) { + // rt_kprintf(stderr, f, a, b, c); + // rt_kprintf(stderr, "\n"); +// } +} + + +alarm() +{ + //longjmp(tohere, -1); +} + + +/* + * readock(timeout, count) reads character(s) from file descriptor 0 + * (1 <= count <= 3) + * it attempts to read count characters. If it gets more than one, + * it is an error unless all are CAN + * (otherwise, only normal response is ACK, CAN, or C) + * Only looks for one if Optiong, which signifies cbreak, not raw input + * + * timeout is in tenths of seconds + */ +readock(timeout, count) +{ + register int c; + static char byt[5]; + int ch; + if (Optiong) + count = 1; /* Special hack for cbreak */ + + //fflush(stdout); + //if (setjmp(tohere)) { + // logent("TIMEOUT\n"); + // return TIMEOUT; + //} + c = 0; + while (1) + { + c = zread(shell->device, 0, byt, 1); + if (c > 0) break; + } + //if (Verbose>5) + // rt_kprintf(stderr, "ret cnt=%d %x %x\n", c, byt[0], byt[1]); + if (c<1) + return TIMEOUT; + if (c==1) + return (byt[0]&0377); + else + while (c) + if (byt[--c] != CAN) + return ERROR; + return CAN; +} +readline(n) +{ + return (readock(n, 1)); +} + + +purgeline() +{ +#ifdef USG + ioctl(iofd, TCFLSH, 0); +#else + lseek(iofd, 0L, 2); +#endif +} + +/* update CRC */ +unsigned +updcrc(c, crc) +register c; +register unsigned crc; +{ + register count; + + for (count=8; --count>=0;) { + if (crc & 0x8000) { + crc <<= 1; + crc += (((c<<=1) & 0400) != 0); + crc ^= 0x1021; + } + else { + crc <<= 1; + crc += (((c<<=1) & 0400) != 0); + } + } + return crc; +} + +/* send cancel string to get the other end to shut up */ +canit() +{ + static char canistr[] = { + ZPAD,ZPAD,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0 + }; + + //printf(canistr); + //fflush(stdout); +} + +/*VARARGS1*/ +logent(a, b, c) +char *a, *b, *c; +{ +// if(Verbose) + // rt_kprintf(stderr, a, b, c); +} + +/* + * return 1 iff stdout and stderr are different devices + * indicating this program operating with a modem on a + * different line + */ +fromcu() +{ + struct stat a, b; + fstat(1, &a); fstat(2, &b); +// return (a.st_rdev != b.st_rdev); +} + +/* + * substr(string, token) searches for token in string s + * returns pointer to token within string if found, NULL otherwise + */ +char * +substr(s, t) +register char *s,*t; +{ + register char *ss,*tt; + /* search for first char of token */ + for (ss=s; *s; s++) + if (*s == *t) + /* compare token with substring */ + for (ss=s,tt=t; ;) { + if (*tt == 0) + return s; + if (*ss++ != *tt++) + break; + } + return NULL; +} + +usage() +{ + +} + +/* + * Get the receiver's init parameters + */ +getzrxinit() +{ + register n; + struct stat f; + + for (n=10; --n>=0; ) { + + switch (zgethdr(Rxhdr, 1)) { + case ZCHALLENGE: /* Echo receiver's challenge numbr */ + stohdr(Rxpos); + zshhdr(ZACK, Txhdr); + continue; + case ZCOMMAND: /* They didn't see out ZRQINIT */ + stohdr(0L); + zshhdr(ZRQINIT, Txhdr); + continue; + case ZRINIT: + Rxflags = Rxhdr[ZF0]; + Rxbuflen = Rxhdr[ZP0] + (Rxhdr[ZP1]<<8); + //signal(SIGINT, SIG_IGN); + mode(2); /* Set cbreak, XON/XOFF, etc. */ + + /* If using a pipe for testing set lower buf len */ + fstat(iofd, &f); + if ((f.st_mode & S_IFMT) != S_IFCHR + && (Rxbuflen == 0 || Rxbuflen > 4096)) + Rxbuflen = 4096; + /* + * If input is not a regular file, force ACK's each 1024 + * (A smarter strategey could be used here ...) + */ + fstat(in, &f); + if (((f.st_mode & S_IFMT) != S_IFREG) + && (Rxbuflen == 0 || Rxbuflen > 1024)) + Rxbuflen = 1024; + + return (sendzsinit()); + case ZCAN: + case TIMEOUT: + return ERROR; + case ZRQINIT: + if (Rxhdr[ZF0] == ZCOMMAND) + continue; + default: + zshhdr(ZNAK, Txhdr); + continue; + } + } + return ERROR; +} + +/* Send send-init information */ +sendzsinit() +{ + register c; + register errors; + + errors = 0; + for (;;) { + stohdr(0L); + zsbhdr(ZSINIT, Txhdr); + zsbdata(Myattn, 1+strlen(Myattn), ZCRCW); + c = zgethdr(Rxhdr, 1); + switch (c) { + case ZCAN: + return ERROR; + case ZACK: + return OK; + default: + if (++errors > 9) + return ERROR; + continue; + } + } +} + +/* Send file name and related info */ +zsendfile(buf, blen) +char *buf; +{ + register c; + + for (;;) { + Txhdr[ZF0] = Lzconv; /* file conversion request */ + Txhdr[ZF1] = Lzmanag; /* file management request */ + Txhdr[ZF2] = Lztrans; /* file transport request */ + Txhdr[ZF3] = 0; + zsbhdr(ZFILE, Txhdr); + zsbdata(buf, blen, ZCRCW); +again: + c = zgethdr(Rxhdr, 1); + switch (c) { + case ZRINIT: + goto again; + case ZCAN: + case TIMEOUT: + case ZABORT: + case ZFIN: + return ERROR; + case ZSKIP: + close(in); return c; + case ZRPOS: + lseek(in, Rxpos, 0); + Txpos = Rxpos; + return zsendfdata(); + case ERROR: + default: + continue; + } + } +} + +/* Send the data in the file */ +zsendfdata() +{ + register c, e; + register newcnt; + register long tcount = 0; + static int tleft = 6; /* Counter for test mode */ + + if (Baudrate > 300) + blklen = 256; + if (Baudrate > 2400) + blklen = KSIZE; + if (Rxbuflen && blklen>Rxbuflen) + blklen = Rxbuflen; +somemore: + //if (setjmp(intrjmp)) { +waitack: + // switch (c = getinsync()) { + // default: + // case ZCAN: + // close(in); + // return ERROR; + // case ZSKIP: + // close(in); + // return c; + // case ZACK: + // case ZRPOS: + // break; + // } +// } + + //signal(SIGINT, onintr); + newcnt = Rxbuflen; + stohdr(Txpos); + zsbhdr(ZDATA, Txhdr); + + /* + * Special testing mode. This should force receiver to Attn,ZRPOS + * many times. Each time the signal should be caught, causing the + * file to be started over from the beginning. + */ + if (Testattn) { + if ( --tleft) + while (tcount < 20000) { + //printf(qbf); + //fflush(stdout); + tcount += strlen(qbf); + } + //signal(SIGINT, SIG_IGN); + canit(); + //sleep(3); + purgeline(); mode(0); + //printf("\nsz: Tcount = %ld\n", tcount); + if (tleft) { + //printf("ERROR: Interrupts Not Caught\n"); + //exit(1); + } + //exit(0); + } + + do { + c = zfilbuf(txbuf, blklen); + if (c < blklen) + e = ZCRCE; + else if (Rxbuflen && (newcnt -= c) <= 0) + e = ZCRCW; + else + e = ZCRCG; + zsbdata(txbuf, c, e); + Txpos += c; + if (e == ZCRCW) + goto waitack; +#ifdef NOTDEF_DOS + if ( !carrier()) { + return ERROR; + } + /* + * If the reverse channel can be tested for data, + * this logic may be used to detect error packets + * sent by the receiver, in place of setjmp/longjmp + * miready() returns non 0 if a character is available + */ + while (miready()) { + if (readline(1) == ZPAD) { + zsbdata(U.ubuf, 0, ZCRCW); + goto somemore; + } + } +#endif + } while (c == blklen); + //signal(SIGINT, SIG_IGN); + + for (;;) { + stohdr(Txpos); + zsbhdr(ZEOF, Txhdr); + switch (getinsync()) { + case ZRPOS: + goto somemore; + case ZRINIT: + close(in); + return OK; + case ZSKIP: + close(in); + return c; + default: + close(in); + return ERROR; + } + } +} + +/* + * Respond to receiver's complaint, get back in sync with receiver + */ +getinsync() +{ + register c; + + for (;;) { + if (Testattn) { + //printf("\r\n\n\n***** Signal Caught *****\r\n"); + Rxpos = 0; c = ZRPOS; + } else + c = zgethdr(Rxhdr, 0); + switch (c) { + case ZCAN: + case ZABORT: + case ZFIN: + case TIMEOUT: + return ERROR; + case ZRPOS: + //clearerr(in); /* In case file EOF seen */ + lseek(in, Rxpos, 0); + Txpos = Rxpos; + return c; + case ZACK: + return c; + case ZRINIT: + case ZSKIP: + close(in); + return c; + case ERROR: + default: + zsbhdr(ZNAK, Txhdr); + continue; + } + } +} +/* Say "bibi" to the receiver, try to do it cleanly */ +saybibi() +{ + for (;;) { + stohdr(0L); + zsbhdr(ZFIN, Txhdr); + switch (zgethdr(Rxhdr, 0)) { + case ZFIN: + sendline('O'); sendline('O'); flushmo(); + case ZCAN: + case TIMEOUT: + return; + } + } +} + +/* Local screen character display function */ +bttyout(c) +{ + //if (Verbose) + // putc(c, stderr); +} + +/* Send command and related info */ +zsendcmd(buf, blen) +char *buf; +{ + register c, errors; + long cmdnum; + +// cmdnum = getpid(); + errors = 0; + for (;;) { + stohdr(cmdnum); + Txhdr[ZF0] = Cmdack1; + zsbhdr(ZCOMMAND, Txhdr); + zsbdata(buf, blen, ZCRCW); +listen: + Rxtimeout = 100; /* Ten second wait for resp. */ + c = zgethdr(Rxhdr, 1); + + switch (c) { + case ZRINIT: + continue; + case ERROR: + case TIMEOUT: + if (++errors > Cmdtries) + return ERROR; + continue; + case ZCAN: + case ZABORT: + case ZFIN: + case ZSKIP: + case ZRPOS: + return ERROR; + default: + if (++errors > 10) + return ERROR; + continue; + case ZCOMPL: + Exitcode = Rxpos; + saybibi(); + return OK; + case ZRQINIT: + vfile("******** RZ *******"); + system("rz"); + vfile("******** SZ *******"); + goto listen; + } + } +} + diff --git a/components/utilities/ZMODEM/ZM.C b/components/utilities/ZMODEM/ZM.C new file mode 100644 index 0000000000..6dceb7ae09 --- /dev/null +++ b/components/utilities/ZMODEM/ZM.C @@ -0,0 +1,480 @@ +/* + * Z M . C + * ZMODEM protocol primitives + * 5-18-86 Chuck Forsberg Omen Technology Inc + * + * Entry point Functions: + * zsbhdr(type, hdr) send binary header + * zshhdr(type, hdr) send hex header + * zgethdr(hdr, eflag) receive header - binary or hex + * zsbdata(buf, len, frameend) send binary data + * zrbdata(buf, len) receive binary data + * stohdr(pos) store position data in Txhdr + * long rclhdr(hdr) recover position offset from header + */ + +//#ifndef CANFDX +#include "zmodem.h" +int Rxtimeout = 100; /* Tenths of seconds to wait for something */ +//#endif +#define ERROR (-1) +static char *frametypes[] = { + "TIMEOUT", + "ERROR", + "ZRQINIT", + "ZRINIT", + "ZSINIT", + "ZACK", + "ZFILE", + "ZSKIP", + "ZNAK", + "ZABORT", + "ZFIN", + "ZRPOS", + "ZDATA", + "ZEOF", + "ZFERR", + "ZCRC", + "ZCHALLENGE", + "ZCOMPL", + "ZCAN", + "ZFREECNT", + "ZCOMMAND", + "ZCACK" +#define FRTYPES 21 /* Total number of frame types in this array */ +}; + +long int rclhdr(char *hdr); +int zputhex(int c); +int zsendline(int c); +int zgethex(void); +int zgeth1(void); +int zrbhdr(char *hdr); +int zrhhdr(char *hdr); +int zdlread(void); +int noxread7(void); + + +/* Send ZMODEM binary header hdr of type type */ +int zsbhdr(int type, char *hdr) +{ + int n; + unsigned short oldcrc; + + vfile("zsbhdr: %s %lx", frametypes[type+2], rclhdr(hdr)); + xsendline(ZPAD); xsendline(ZDLE); xsendline(ZBIN); + + zsendline(type); oldcrc = updcrc(type, 0); + + for (n=4; --n >= 0;) { + zsendline(*hdr); + oldcrc = updcrc(*hdr++, oldcrc); + } + oldcrc = updcrc(0,updcrc(0,oldcrc)); + zsendline(oldcrc>>8); + zsendline(oldcrc); + if (type != ZDATA) + flushmo(); + return 0; +} + +/* Send ZMODEM HEX header hdr of type type */ +int zshhdr(int type, char *hdr) +{ + int n; + unsigned short oldcrc; + + vfile("zshhdr: %s %lx", frametypes[type+2], rclhdr(hdr)); + + sendline(ZPAD); sendline(ZPAD); sendline(ZDLE); sendline(ZHEX); + zputhex(type); + + oldcrc = updcrc(type, 0); + for (n=4; --n >= 0;) { + zputhex(*hdr); oldcrc = updcrc(*hdr++, oldcrc); + } + oldcrc = updcrc(0,updcrc(0,oldcrc)); + zputhex(oldcrc>>8); zputhex(oldcrc); + + /* Make it printable on remote machine */ + sendline(015); sendline(0212); /*012*/ + /* + * Uncork the remote in case a fake XOFF has stopped data flow + */ + if (type != ZFIN) + sendline(021); + flushmo(); + return 0; +} + +/* + * Send binary array buf of length length, with ending ZDLE sequence frameend + */ +int zsbdata(char *buf, int length, int frameend) +{ + register unsigned short oldcrc; + + vfile("zsbdata: length=%d end=%x", length, frameend); + oldcrc = 0; + for (;--length >= 0;) { + zsendline(*buf); + oldcrc = updcrc(*buf++, oldcrc); + } + xsendline(ZDLE); xsendline(frameend); + oldcrc = updcrc(frameend, oldcrc); + + oldcrc = updcrc(0,updcrc(0,oldcrc)); + zsendline(oldcrc>>8); + zsendline(oldcrc); + if (frameend == ZCRCW) + flushmo(); + return 0; +} + +/* + * Receive binary array buf of max length with ending ZDLE sequence + * and CRC. Returns the ending character or error code. + */ +int zrbdata(char *buf, int length) +{ + int c; + unsigned short oldcrc; + int d; + + oldcrc = Rxcount = 0; + for (;;) { + if ((c = zdlread()) & ~0377) { + switch (c) { + case GOTCRCE: + case GOTCRCG: + case GOTCRCQ: + case GOTCRCW: + oldcrc = updcrc((d=c)&0377, oldcrc); + if ((c = zdlread()) & ~0377) + goto badcrc; + oldcrc = updcrc(c, oldcrc); + if ((c = zdlread()) & ~0377) + goto badcrc; + oldcrc = updcrc(c, oldcrc); + if (oldcrc & 0xFFFF) { +badcrc: + zperr("Bad data packet CRC"); + return ERROR; + } + vfile("zrbdata: Rxcount = %d ret = %x", + Rxcount, d); + return d; + case GOTCAN: + zperr("ZMODEM: Sender Canceled"); + return ZCAN; + case TIMEOUT: + zperr("ZMODEM data packet TIMEOUT"); + return c; + default: + zperr("ZMODEM bad data packet ret=%x", c); + return c; + } + } + if (--length < 0) { + zperr("ZMODEM binary data packet too long"); + return ERROR; + } + ++Rxcount; + *buf++ = c; + oldcrc = updcrc(c, oldcrc); + continue; + } +} + +/* + * Read a ZMODEM header to hdr, either binary or hex. + * eflag controls local display of non zmodem characters: + * 0: no display + * 1: display printing characters only + * 2: display all non ZMODEM characters + * On success, set Zmodem to 1 and return type of header. + * Otherwise return negative on error + */ +int zgethdr(char *hdr, int eflag) +{ + int c, n; + + n = Baudrate; /* Max characters before start of frame */ +again: + Rxframeind = Rxtype = 0; + switch (c = noxread7()) { + case TIMEOUT: + goto fifi; + case ZDLE: + if (noxread7() == ZDLE) { + c = ZCAN; goto fifi; + } + /* **** FALL THRU TO **** */ + default: + if ( --n == 0) { + zperr("ZMODEM Garbage count exceeded"); + return(ERROR); + } + if (eflag && ((c &= 0177) & 0140)) + bttyout(c); + else if (eflag > 1) + bttyout(c); + goto again; + case ZPAD: + break; + } +splat: + switch (c = noxread7()) { + case ZPAD: + goto splat; + case TIMEOUT: + goto fifi; + default: + goto again; + case ZDLE: + break; + } + + switch (c = noxread7()) { + case TIMEOUT: + goto fifi; + case ZBIN: + Rxframeind = ZBIN; + c = zrbhdr(hdr); + break; + case ZHEX: + Rxframeind = ZHEX; + c = zrhhdr(hdr); + break; + case ZDLE: + if (noxread7() == ZDLE) { + c = ZCAN; goto fifi; + } + /* **** FALL THRU TO **** */ + default: + goto again; + } + Rxpos = hdr[ZP3] & 0377; + Rxpos = (Rxpos<<8) + (hdr[ZP2] & 0377); + Rxpos = (Rxpos<<8) + (hdr[ZP1] & 0377); + Rxpos = (Rxpos<<8) + (hdr[ZP0] & 0377); +fifi: + switch (c) { + case GOTCAN: + c = ZCAN; + /* **** FALL THRU TO **** */ + case ZNAK: + case ZCAN: + case ERROR: + case TIMEOUT: + zperr("ZMODEM: Got %s header", frametypes[c+2]); + default: + if (c >= -2 && c <= FRTYPES) + vfile("zgethdr: %s %lx", frametypes[c+2], Rxpos); + else + vfile("zgethdr: %d %lx", c, Rxpos); + } + return c; +} + +/* Receive a binary style header (type and position) */ +int zrbhdr(char *hdr) +{ + int c, n; + unsigned short oldcrc; + + if ((c = zdlread()) & ~0377) + return c; + Rxtype = c; + oldcrc = updcrc(c, 0); + + for (n=4; --n >= 0;) { + if ((c = zdlread()) & ~0377) + return c; + oldcrc = updcrc(c, oldcrc); + *hdr++ = c; + } + if ((c = zdlread()) & ~0377) + return c; + oldcrc = updcrc(c, oldcrc); + if ((c = zdlread()) & ~0377) + return c; + oldcrc = updcrc(c, oldcrc); + if (oldcrc & 0xFFFF) { + zperr("Bad Header CRC"); return ERROR; + } + Zmodem = 1; + return Rxtype; +} + +/* Receive a hex style header (type and position) */ +int zrhhdr(char *hdr) +{ + int c; + unsigned short oldcrc; + int n; + + if ((c = zgethex()) < 0) + return c; + Rxtype = c; + oldcrc = updcrc(c, 0); + + for (n=4; --n >= 0;) { + if ((c = zgethex()) < 0) + return c; + oldcrc = updcrc(c, oldcrc); + *hdr++ = c; + } + if ((c = zgethex()) < 0) + return c; + oldcrc = updcrc(c, oldcrc); + if ((c = zgethex()) < 0) + return c; + oldcrc = updcrc(c, oldcrc); + if (oldcrc & 0xFFFF) { + zperr("Bad Header CRC"); return ERROR; + } + if (readline(1) == '\r') /* Throw away possible cr/lf */ + readline(1); + Zmodem = 1; return Rxtype; +} + +/* Send a byte as two hex digits */ +int zputhex(int c) +{ + static char digits[] = "0123456789abcdef"; + + if (Verbose>4) + vfile("zputhex: %x", c); + sendline(digits[(c&0xF0)>>4]); + sendline(digits[(c)&0xF]); + return 0; +} + +/* Send character c with ZMODEM escape sequence encoding */ +int zsendline(int c) +{ + switch (c & 0377) { + case ZDLE: + case 021: + case 023: + case 0221: + case 0223: + xsendline(ZDLE); + c ^= 0100; + /* **** FALL THRU TO **** */ + default: + xsendline(c); + } + return 0; +} + +/* Decode two lower case hex digits into an 8 bit byte value */ +int zgethex(void) +{ + int c; + + c = zgeth1(); + if (Verbose>4) + vfile("zgethex: %x", c); + return c; +} +int zgeth1(void) +{ + int c, n; + + if ((c = noxread7()) < 0) + return c; + n = c - '0'; + if (n > 9) + n -= ('a' - ':'); + if (n & ~0xF) + return ERROR; + if ((c = noxread7()) < 0) + return c; + c -= '0'; + if (c > 9) + c -= ('a' - ':'); + if (c & ~0xF) + return ERROR; + c += (n<<4); + return c; +} + +/* + * Read a byte, checking for ZMODEM escape encoding + * including CAN-CAN which represents a quick abort + */ +int zdlread(void) +{ + int c; + + if ((c = readline(Rxtimeout)) != ZDLE) + return c; + if ((c = readline(Rxtimeout)) < 0) + return c; + switch (c) { + case ZDLE: + return GOTCAN; + case ZCRCE: + case ZCRCG: + case ZCRCQ: + case ZCRCW: + return (c | GOTOR); + case ZRUB0: + return 0177; + case ZRUB1: + return 0377; + default: + if ((c & 0140) == 0100) + return (c ^ 0100); + break; + } + zperr("Got bad ZMODEM escape sequence %x", c); + return ERROR; +} + +/* + * Read a character from the modem line with timeout. + * Eat parity, XON and XOFF characters. + */ +int noxread7(void) +{ + int c; + + for (;;) { + if ((c = readline(Rxtimeout)) < 0) + return c; + switch (c &= 0177) { + case XON: + case XOFF: + continue; + default: + return c; + } + } +} + +/* Store long integer pos in Txhdr */ +int stohdr(long int pos) +{ + Txhdr[ZP0] = pos; + Txhdr[ZP1] = pos>>8; + Txhdr[ZP2] = pos>>16; + Txhdr[ZP3] = pos>>24; + return 0; +} + +/* Recover a long integer from a header */ +long +int rclhdr(char *hdr) +{ + long int l; + + l = (hdr[ZP3] & 0377); + l = (l << 8) | (hdr[ZP2] & 0377); + l = (l << 8) | (hdr[ZP1] & 0377); + l = (l << 8) | (hdr[ZP0] & 0377); + return l; +} + diff --git a/components/utilities/ZMODEM/ZMODEM.DOC b/components/utilities/ZMODEM/ZMODEM.DOC new file mode 100644 index 0000000000..3b2149c884 --- /dev/null +++ b/components/utilities/ZMODEM/ZMODEM.DOC @@ -0,0 +1,2056 @@ + + + + The ZMODEM Asynchronous Inter Application File Transfer Protocol + + Chuck Forsberg + + Omen Technology Inc + + + Chuck Forsberg + Omen Technology Inc + 17505-V Northwest Sauvie Island Road + Portland Oregon 97231 + Voice: 503-621-3406 + Modem (Telegodzilla): 503-621-3746 Speed 1200,300 + Compuserve: 70715,131 + UUCP: ...!tektronix!reed!omen!caf + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Chapter 0 rev051486 Printed 5-16-86 1 + + + + + + + +Chapter 0 rev051486 Printed 5-16-86 2 + + + +1. INTENDED AUDIENCE + +This document is intended for systems programmers and other technically +qualified people who choose and implement asynchronous file transfer +protocols over dial-up networks and related environments. + + +2. ACKNOWLEDGMENTS + +Encouragement and suggestions by Stuart Mathison, Thomas Buck, John Wales, +Ward Christensen, and Irv Hoff are gratefully acknowledged. + + +3. RELATED DOCUMENTS + +The following files should be available for reference while studying this +document: + +YMODEM.DOC Describes the XMODEM and YMODEM file transfer protocols + +ZMODEM.H Provides definitions for the manifest constants referenced + herein. + +rz.c, sz.c, rbsb.c Unix source code for operating ZMODEM programs. + +rz.1, sz.1 Manual pages for rz and sz. + +zm.c, zmodem.h Operating system independent ZMODEM subroutines, header + file. + + +4. ROSETTA STONE + +Here are some definitions which reflect the current vernacular in the +computer media. The attempt here is identify the file transfer protocol +rather than specific programs. + +Frame A ZMODEM frame consists of a header packet and 0 or more data + packets. + +XMODEM refers to the original 1979 file transfer etiquette introduced by + Ward Christensen's 1979 MODEM2 program. It's also called the + MODEM or MODEM2 protocol. Some who are unaware of MODEM7's + unusual batch file mode call it MODEM7. Other aliases include + "CP/M Users's Group" and "TERM II FTP 3". This protocol is + supported by every serious communications program because of its + universality, simplicity, and reasonable performance. + +XMODEM/CRC replaces XMODEM's 1 byte checksum with a two byte Cyclical + Redundancy Check (CRC-16), giving modern error detection + protection. + + + +Chapter 4 rev051486 Printed 5-16-86 2 + + + + + + + +Chapter 4 rev051486 Printed 5-16-86 3 + + + +YMODEM refers to the XMODEM/CRC protocol with the throughput and/or batch + transmission enhancements described in YMODEM.DOC. + +ZMODEM Zmodem is a second generation streaming protocol for text and + binary file transmission between applications running on + microcomputers and mainframes. + + +5. WHY DEVELOP ZMODEM? + +Since its development half a decade ago, the Ward Christensen MODEM +protocol has enabled a wide variety of computer systems to interchange +data. There is hardly a communications program that doesn't at least +claim to support this protocol, now called XMODEM. + +Advances in computing, modems and networking have spread the XMODEM +protocol far beyond the micro to micro environment for which it was +designed. These application have exposed some weaknesses: + + + The user interface is suitable for computer hobbyists. Three or four + commands must be keyboarded to transfer each file. + + + The short block length causes throughput to suffer when used with + timesharing systems, packet switched networks, satellite circuits, + and buffered (error correcting) modems. + + + The 8 bit checksum and unprotected transactions allow undetected + errors and disrupted file transfers. + + + Only one file can be sent per command. The file name has to be given + twice, first to the sending program and then again to the receiving + program. + + + The transmitted file accumulates as many as 127 extraneous bytes. + + + The modification date and other file attributes are lost. + + + XMODEM requires complete 8 bit transparency, all 256 codes. XMODEM + will not operate over some networks that need flow control. + +A number of other protocols have been developed over the years, but none +have displaced XMODEM to date. + + + Lack of public domain documentation and example programs have kept + proprietary protocols such as MNP, Blast, and others tightly bound to + the fortunes of their suppliers. + + + Hardware and/or software complexity discourages the widespread + application of BISYNC, SDLC, HDLC, X.25, and X.PC protocols. + + + + + +Chapter 5 rev051486 Printed 5-16-86 3 + + + + + + + +Chapter 5 rev051486 Printed 5-16-86 4 + + + + + Link level protocols such as X.25, X.PC, and MNP do not manage + application to application file transfers. + + + The Kermit protocol was developed to allow file transfers in + environments hostile to XMODEM. The performance compromises + necessary to accomodate non transparent environments limit Kermit's + efficiency. Even with completely transparent channels, Kermit + control character quoting limits the efficiency of binary file + transfers to about 75 per cent.[1] + + Kermit Sliding Windows ("SuperKermit") improves throughput over + networks at the cost of increased complexity. SuperKermit state + transitions are encoded in a special language "wart" which requires a + C compiler. The SuperKermit C code requires full duplex + communications and the ability to check for the presence of + characters in the input queue, precluding its implementation on some + operating systems. + + A number of submodes are used in various Kermit programs, including + different methods of transferring binary files. Two Kermit programs + will mysteriously fail to operate with each other if these submodes + are not matched. + +A number of extensions to the XMODEM protocol have been made under the +collective name YMODEM. + + + YMODEM-k uses 1024 byte blocks to reduce the overhead from transmission + delays by 87 per cent compared to XMODEM, but network delays can still + degrade performance. Some networks may not be transmit the 1024 byte + packets unmodified. + + + The handling of files that are not a multiple of 1024 or 128 bytes is + awkward, especially if the file length is not known, or changes during + transmission. + + + YMODEM-g provides efficient batch file transfers, preserving the exact + file length and file modification date. YMODEM-g is essentially + insensitive to network delays. Because it does not support error + recovery, YMODEM-g is usually used hardwired or with a reliable link + level protocol. IF YMODEM-g detects a CRC error, data transfers are + aborted. YMODEM-g is easy to implement because it closely resembles + XMODEM-CRC. + +Another XMODEM "extension" is protocol cheating, referred to as "Turbo +Download" and OverThruster. [2] These sometimes improve XMODEM throughput + + +__________ + + 1. Some Kermit programs support run length encoding. + + + + +Chapter 5 rev051486 Printed 5-16-86 4 + + + + + + + +Chapter 5 rev051486 Printed 5-16-86 5 + + + +at the expense of error recovery. + +The ZMODEM Protocol is proposed as a means of addressing the weaknesses +described above while maintaining as much of XMODEM's simplicity and prior +art as possible. + + + +6. ZMODEM Protocol Design Criteria + +The design of a file transfer protocol is an engineering compromise +between conflicting requirements: + +6.1 Ease of Use + + + ZMODEM allows either program to initiate file transfers, passing + commands and/or modifiers to the other program. + + + File names need be entered only once, menu selections are possible. + + + Wild Card names may be used with batch transfers. + + + Minimum keystrokes required to initiate transfers. + + + ZRQINIT packet sent by sending program can trigger automatic downloads. + + + ZMODEM can step down to YMODEM if the other end does not support + ZMODEM.[1] + +6.2 Throughput + +ZMODEM is designed for optimum performance with minimum degradation caused +by delays introduced by packet switched networks and timesharing systems. + +ZMODEM is optimized for best throughput when line hits occur infrequently. +This assumption markedly reduces code complexity and memory requirements. +ZMODEM protocol features enhance rapid error recovery compared to network +compatible XMODEM implementations. + +It is assumed that many transfers will originate from a timesharing system +connected to a packet switched network. ZMODEM provides features to allow +for simple, efficient implementation on timesharing hosts. + + + +__________________________________________________________________________ + + 2. Omen Technology Trademark + + 1. Provided the transmission medium accomodates YMODEM. + + + + +Chapter 6 rev051486 Printed 5-16-86 5 + + + + + + + +Chapter 6 rev051486 Printed 5-16-86 6 + + + +File transfers begin immediately regardless of which program is started +first, without the 10 second delay associated with XMODEM. + + +6.3 Integrity and Robustness + +All packets are protected with 16 bit CRC. Proprietary alogrithyms[2] are +not needed for reliable transfers. + +A security challenge guards againgst Trojan Horse messages. + +6.4 Ease of Implementation + +ZMODEM accomodates a wide variety of systems: + + + Microcomputers that cannot overlap disk and serial i/o + + + Microcomputers that cannot overlap serial send and receive + + + Computers and/or networks requiring XON/XOFF flow control + + + Computers that cannot check the serial input queue for the presence of + data without having to wait for the data to arrive. + +Although ZMODEM provides "hooks" for multiple "threads", ZMODEM is not +intended to replace link level protocols such as X.25. + +ZMODEM accomodates network and timesharing system delays by continuously +transmitting data unless the receiver interrupts the sender to request +retransmission of garbled data. ZMODEM in effect uses the entire file as +a window.[3] + +ZMODEM provides a general purpose application to application file transfer +protocol which may be used directly or with with reliable link level +protocols such as X.25, MNP, Fastlink, etc. + + +7. ZMODEM BASICS + + + + + + + +__________ + + 2. Unique to Professional-YAM, PowerCom, etc. + + 3. Streaming strategey is discussed in a coming chapter. + + + + +Chapter 7 rev051486 Printed 5-16-86 6 + + + + + + + +Chapter 7 rev051486 Printed 5-16-86 7 + + + +7.1 Packetization + +ZMODEM frames somewhat different from X/YMODEM blocks. X/YMODEM blocks +are not used for the following reasons: + + + Block numbers are limited to 256 + + + No provision for variable length blocks + + + Line hits corrupt protocol signals, causing failed file transfers. In + particular, modem errors sometimes generate false block numbers, false + EOTs and false ACKs. False ACKs are the most troublesome as they cause + the sender to lose synchronization with the receiver. + + State of the art X/YMODEM programs such as Professional-YAM and + PowerCom overcome some of these weaknesses with clever proprietary + code, but a stronger protocol is desired. + + + It is difficult to determine the beginning and ends of X/YMODEM blocks + when line hits cause a loss of synchronization. This precludes rapid + error recovery. + +7.2 Link Escape Encoding + +ZMODEM acheives data transparency by extending the 8 bit character set +(256 codes) with escape sequences based on the ZMODEM data link escape +character ZDLE.[1] + +Link Escape coding permits variable length data packets without the +overhead of a separate byte count. It allows the beginning of frames to +be detected without special timing techniques, facilitating rapid error +recovery. + +Link Escape coding does add some overhead. The worst case, a file +consisting entirely of ZDLE characters, would incur a 50% overhead. + +The ZDLE character is special. ZDLE represents a control sequence of some +sort. If a ZDLE character appears in the data sent within a binary +packet, it is prefixed with ZDLE, then sent as ZDLEE. + +The value for ZDLE is octal 030 (ASCII CAN). This particular value was +chosen to allow a string of CAN characters to abort a ZMODEM session, +compatible with X/YMODEM session abort. + + + +__________ + + 1. This and other constants are defined in the zmodem.h include file. + Please note that constants with a leading 0 are octal constants in C. + + + + +Chapter 7 rev051486 Printed 5-16-86 7 + + + + + + + +Chapter 7 rev051486 Printed 5-16-86 8 + + + +Since CAN is not used for normal terminal operations, communications +programs can monitor the data flow for ZDLE. The following characters can +be scanned to detect the ZRQINIT packet, the invitation to automatically +download commands or files. + +Two successive CAN characters will abort a ZMODEM session. Experience +with YMODEM file transfers suggests that this does not impair the +robustness of the protocol. A minimum of 8 CAN are sent, so the ZMODEM +subroutines can be modified to require more successive CAN characters to +signal an abort. + +The receiving program will decode any sequence of ZDLE followed by a byte +with bit 6 set and bit 5 reset (upper case letter, either parity) to the +equivalent control character by inverting bit 6. This allows the +transmitter to escape any control character that cannot be sent by the +communications medium. The ZMODEM software currently escapes ZDLE, 021, +0221, 023, and 0223. In addition, the receiver recognizes escapes for +0177 and 0377 should these characters need to be escaped. + +7.3 Header Packet Information + +All ZMODEM frames begin with a header packet which may be sent in binary +or HEX form. ZMODEM uses a single routine to recognize binary and hex +header packets. Either form of the header packet contains the same raw +information: + + + A type byte[2] Future extensions to ZMODEM may use the high order bits + of the type byte to indicate thread selection. + + + Four bytes of data indicating flags and/or numeric quantities depending + on the packet type + + Figure 1. Order of Bytes in Header Packet + + + TYPE: packet Type + F0: Flags least significant byte + P0: file Position least significant + P3: file Position most significant + + TYPE F3 F2 F1 F0 + -------------- + TYPE P0 P1 P2 P3 + + + +__________ + + 2. The packet types are cardinal numbers beginning with 0 to minimize + state transition table memory requirements. + + + + +Chapter 7 rev051486 Printed 5-16-86 8 + + + + + + + +Chapter 7 rev051486 Printed 5-16-86 9 + + + +7.4 Binary Header Packet + +A binary header packet is only sent by the sending program to the +receiving program. + +A binary header packet begins with the sequence ZPAD, ZDLE, ZBIN. + +The frame type byte is ZDLE encoded. + +The four position/flags bytes are ZDLE encoded. + +A two byte CRC of the frame type and position/flag bytes is ZDLE encoded. + +0 or more binary data packets will follow depending on the frame type. + +The function zsbhdr transmits a binary header packet. The function +zgethdr receives a binary or hex header packet. + + Figure 2. Binary Header Packet + * * ZDLE TYPE F3/P0 F2/P1 F1/P2 F0/P3 CRC-1 CRC-2 + + +7.5 HEX Header Packet + +The receiver sends responses in hex header packets. The sender also uses +hex header packets when they are not followed by binary data packets. + +Hex encoding is required to support XON/XOFF flow control. The hex header +receiving routine ignores flow control characters. + +Use of Kermit style encoding for control and paritied characters was +considered and rejected because of increased possibility of interacting +with some timesharing systems's line edit functions. Use of HEX packets +from the receiving program allows control characters to be used to +interrupt the sender when errors are detected. Except for header packet +types that imply data packets to follow, a HEX header packet may be used +in place of a binary header packet. + +A hex header packet begins with the sequence ZPAD, ZPAD, ZDLE, ZHEX. The +zgethdr routine synchronizes in the ZPAD-ZDELE sequence. The extra ZPAD +allows other parts of the program to detect a ZMODEM packet and then call +zgethdr to receive the packet. + +The type byte, the four position/flag bytes, and the CRC thereof are sent +in hex using the character set 01234567890abcdef. Upper case hex digits +are not allowed; they false trigger X/YMODEM programs. + +A carriage return, line feed, and XON are appended to the HEX header +packet but are not considered to be part of it. The CR/LF aids debugging +from printouts. The XON releases the sender from spurious XOFF flow +control characters generated by line noise, a common occurrence. + + + +Chapter 7 rev051486 Printed 5-16-86 9 + + + + + + + +Chapter 7 rev051486 Printed 5-16-86 10 + + + +0 or more ASCII Encoded data packets will follow depending on the frame +type. + +The function zshhdr sends a hex header packet. + + Figure 3. HEX Header Packet + * * ZDLE TYPE F3/P0 F2/P1 F1/P2 F0/P3 CRC-1 CRC-2 CR LF XON + +(TYPE, F3...F0, CRC-1, and CRC-2 are each sent as two hex digits.) + + +7.6 Binary Data Packets + +Binary data packets immediately follow the associated binary header +packet. A binary data packet contains 0 to 1024 bytes of data. +Recommended length values are 256 bytes below 4800 bps, 1024 above 4800 +bps or when the data link is known to be relatively error free. + +No padding is used with binary data packets. The data bytes are ZDLE +encoded and transmitted. A ZDLE and frameend are then sent, followed by +two ZDLE encoded CRC bytes. The CRC accumulates the data bytes and +frameend. + +The function zsbdata sends a binary data packet. The function zrbdata +receives a binary data packet. + +7.7 ASCII Encoded Data Packet + +The format of ASCII Encoded data packets is not currently specified. +These would be used for server commands, etc. + + +8. PROTOCOL TRANSACTION OVERVIEW + +As with the XMODEM recommendation, ZMODEM timing is receiver driven. The +transmitter should not time out at all, except to abort the program if no +packets are received for an extended period of time, say one minute.[1] + +To start a ZMODEM file transfer session, the sending program is called +with the names of the desired file(s) and option(s). + +The sending program sends the string "rz\r" to invoke the receiving +program from a possible command mode. The "rz" followed by carriage +return activates a ZMODEM receive program or command if it were not +already active. + + +__________ + + 1. Special considerations apply when sending commands. + + + + +Chapter 8 rev051486 Printed 5-16-86 10 + + + + + + + +Chapter 8 rev051486 Printed 5-16-86 11 + + + +The sender may then display a message intended for human consumption, such +as a list of the files requested, etc. + +Then the sender sends a ZRQINIT packet. The ZRQINIT packet causes a +previously started receive program to send its ZRINIT packet without +delay. + +In an interactive or conversational mode, the receiving application may +monitor the data stream for ZDLE. The following characters may be scanned +for B000000 indicating a ZRQINIT packet, a command to download a command +or data. + +The sending program awaits a command from the receiving program to start +file transfers. If a "C", "G", or NAK is received, an XMODEM or YMODEM +file transfer is indicated, and file transfer(s) use the X/YMODEM +protocol. Note: With ZMODEM and YMODEM Batch, the sending program +provides the file name, but not with XMODEM. + +When the ZMODEM receive program starts, it immediately sends a ZRINIT +packet to initiate ZMODEM file transfers, or a ZCHALLENGE packet to verify +the sending program. The receive program resends its packet at repsonse +time intervals for a suitable period of time (40 seconds typical) before +falling back to X/YMODEM protocol. If the receiving program receives a +ZRQINIT packet, it resends the ZRINIT packet. If the sending program +receives the ZCHALLENGE packet, it places the data in ZP0...ZP3 in an +answering ZACK packet. + +If the receiving program receives a ZRINIT packet, it is an echo +indicating that the sending program is not operational. + +Eventually the sending program correctly receives the ZRINIT packet. + +The sender may then respond with an optional ZSINIT frame to set the +receiving program's Attention string. The receiver sends a ZACK packet in +response, containing the serial number of the receiving program, or 0. + +The sender then sends a ZFILE header with ZMODEM Conversion, Management, +and Transport options[2] followed by a ZCRCW data packet containing the +file name, file length, modification date, and other information identical +to that used by YMODEM Batch. + +The receiving program should insure the pathname and options are +compatible with its operating environment and local security requirements. + + + + +__________ + + 2. See below, under ZFILE packet type. + + + + +Chapter 8 rev051486 Printed 5-16-86 11 + + + + + + + +Chapter 8 rev051486 Printed 5-16-86 12 + + + + If the receiver has a file with the same name and length, + it may respond with a ZCRC packet, which requires the + sender to permorm a 16 bit CRC on the file and transmit the + CRC in ZP0...ZP1 of a ZCRC packet. The receiver uses this + information to determine whether to accept the file or skip + it. This sequence is triggered by the ZMCRC Management + Option. + +The receiver may then respond with a ZSKIP packet, which causes the +sender to process the next file (if any) in the batch. + +A ZRPOS packet from the receiver initiates transmission of the file data +starting at the offset in the file specified in the ZRPOS packet. +Normally the receiver specifies the data transfer begin begin at offset 0 +in the file. + The receiver may start the transfer further down in the + file. This allows a file transfer interrupted by a loss + or carrier or system crash to be completed on the next + connection without requiring the entire file to be + retransmitted.[3] If downloading a file from a timesharing + system that becomes sluggish, the transfer can be + interrupted and resumed later with no loss of data. + +The sender sends a ZDATA binary header packet (with file position) +followed by one or more data packets. + +The receiver compares the file position in the ZDATA header with the +number of characters successfully received to the file. If they do not +agree, a ZRPOS error response is generated to force the sender to the +right position within the file.[4] + +A data packet terminated by ZCRCGO and CRC does not elicit a response +unless an error is detected; more data packet(s) follow immediately. + + ZCRCQ data packets expect a ZACK response (with the file + offset) if no error, otherwise a ZRPOS response (with the + last good file offset). Another data packet continues + immediately. ZCRCQ packets are not used if the receiver + does not indicate FDX ability with the CANFDX bit. + +ZCRCW data packets expect a response before the next frame is sent. If +the receiver does not indicate overlapped I/O capability with the + + +__________ + + 3. This does not apply to files that have been translated. + + 4. If the ZMSPARS option is used, the receiver instead seeks to position + in the ZDATA packet. + + + + +Chapter 8 rev051486 Printed 5-16-86 12 + + + + + + + +Chapter 8 rev051486 Printed 5-16-86 13 + + + +CANOVIO bit, or by setting a buffer size, the sender uses the ZCRCW to +allow the receiver to write its buffer before sending more data. + + A zero length data frame may be used as a sending idle + packet to prevent the receiver from timing out in case + data is not immediately available to the sender. + +In the absence of fatal error, the sender eventually encounters end of +file. If the end of file is encountered within a frame, the frame is +closed with a ZCRCE data packet which does not elicit a response +except in case of error. + +The sender sends a ZEOF packet with the file ending offset equal to +the number of characters in the file. The receiver compares this +number with the number of characters received. If the receiver has +received all of the file, it closes the file. If the file close was +satisfactory, the receiver responds with ZRINIT. If the receiver has +not received all the bytes of the file, the receiver sends ZRPOS with +the current file offset, forcing the sender to resend the missing +data. (If the receiver cannot properly close the file, a ZFERR packet +is sent.) + + After all files are processed, any further protocol + errors should not prevent the sending program from + returning with a success status. + +The sender closes the session with a ZEXIT header packet. The +receiver acknowledges this with its own ZEXIT packet. + +When the sender receives the acknowledging packet, it sends two +characters, "OO" (Over and Out) and exits to the operating system or +application that invoked it. The receiver waits briefly for the "O" +characters, then exits whether they were received or not. + +8.1 Session Cancel Packet + +The Cancel packet consists of two ZPAD characters, eight CAN +characters, and an optional ten backspace characters. First, the +Attn sequence is executed if the receiving program has been receiving +data in streaming mode. The ZPAD characters allow sending programs +that sample the reverse data stream to check for a single character +code indicating a packet from the receiver. The trailing backspace +characters attempt to erase the effects of the other characters if +they are received by a command interpreter. + + static char canistr[] = { +ZPAD,ZPAD,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0 }; + + + + + + + +Chapter 9 rev051486 Printed 5-16-86 13 + + + + + + + +Chapter 9 rev051486 Printed 5-16-86 14 + + + +9. ZMODEM STREAMING TECHNIQUES + +ZMODEM allows choices of several data streaming methods selected +according to the limitations of the sending environment, receiving +environment, and transmission channel(s). + + +9.1 Full Streaming with Sampling + +If the computers can overlap serial I/O with disk I/O, and if the +sender can sample the reverse channel for the presence of data +without having to wait, full streaming can be used with no Attn +sequence required. The sender begins data transmission with a ZDATA +header and continuous ZCRCG data packets. When the receiver detects +an error, it executes the Attn sequence and then sends a ZRPOS packet +to force the sender back to the correct position within the file. At +the end of each transmitted packet, the sender checks for the +presence of an error packet from the receiver. To do this, the +sender may sample the reverse data stream for the presence of a ZPAD +character. + +Such a program would sample the reverse channel for ZPAD. If seen, +an empty ZCRCW data packet is sent (in case the receiver was still +reading packets) and then the receiver's response packet is read and +acted upon. The code fragment in sz.c beginning at NOTDEF_DOS would +perform this function. + + +9.2 Full Streaming with Interrupt + +The method above cannot be used if if the reverse data stream cannot +be sampled without entering an I/O wait. An alternate method is to +instruct the receiver to interrupt the sending program when an error +is detected. + +The receiver can interrupt the sender with a control character, break +signal, or combination thereof, as specified in the ZSINIT frame sent +by the sending program. + +When the sending program "catches" this interrupt, it reads a HEX +packet (normally ZRPOS) from the receiver and takes appropriate +action. The Unix sb.c program uses a setjmp/longjmp call and the +getinsync() function to read the receiver's error packet and take +appropriate action. + + + + + + + + + + +Chapter 9 rev051486 Printed 5-16-86 14 + + + + + + + +Chapter 9 rev051486 Printed 5-16-86 15 + + + +9.3 Full Streaming with a Sliding Window + +If none of the above methods is applicable, hope is not yet lost. If +the sender can buffer responses from the receiver, the sender can use +ZCRCQ packets to get ACKs from the receiver without interrupting the +transmission of data. After a sufficient number of ZCRCQ packets +have been sent, the sender can read one of the one or more packets +that should have arrived in it's receive interrupt buffer. + +A problem with this method is the probability of wasting an excessive +amount of time responding to the receiver's error packet. + +9.4 No Streaming + +If the receiver cannot overlap serial and disk I/O, it uses the +ZRINIT frame to specify a buffer length which the sender will not +overflow. The sending program sends a ZCRCW packet and waits for an +ZACK packet before sending the next segment of the file. + +If the sending program supports reverse data stream sampling or +interrupt, error recovery will be faster (on average) than a protocol +(such as YMODEM) that sends "monolithic" blocks. + + +10. ATTENTION SEQUENCE + +The receiving program sends the Attn sequence whenever it detects an +error and needs to interrupt the sending program. + +The default Attn string value is empty (no Attn sequence). The +receiving program resets Attn to the empty default before each +transfer session. + +The sender speficies the Attn sequence in its optional ZSINIT frame. +The Attn string is terminated with a null. + +Two meta-characters perform special functions: + + + \335 (octal) Sends a break signal + + + \336 (octal) Pauses one second + + +11. PACKET/FRAME TYPES + +The numeric values for the values shown in boldface are given in +zmodem.h. + + + + + + + +Chapter 11 rev051486 Printed 5-16-86 15 + + + + + + + +Chapter 11 rev051486 Printed 5-16-86 16 + + + +11.1 ZRQINIT + +Sent once by the sending program, to trigger the receiving program to +send its ZRINIT packet. This aviods the aggravatimg startup delay +associated with XMODEM and Kermit transfers. + +ZF0 contains ZCOMMAND if the program is attempting to send a command, +0 otherwise. + +11.2 ZRINIT + +Sent by the receiving program. ZF0 and ZF1 contain the bitwise or +of the receiver capability flags: +#define CANFDX 1 /* Rx can send and receive FDX */ +#define CANOVIO 2 /* Rx can receive during disk I/O */ +#define CANBRK 4 /* Rx can send a break signal */ +#define CANCRY 8 /* Receiver can decrypt */ + +ZP0 and ZP1 contain the size of the receiver's buffer in bytes, or 0 +if nonstop I/O is allowed. + +11.3 ZSINIT + +Sender sends capability flags (currently all 0) (none currently +defined) followed by a binary data packet terminated with ZCRCW. The +data packet contains the null terminated Attn sequence, maximum +length 32 bytes including the terminating null. + +11.4 ZACK + +Acknowedgement to ZSINIT header packet, ZCHALLENGE header packet, or +ZCRCW data packet. ZP0 to ZP3 contain file offset. Response to +ZCHALLENGE contains the same 32 bits as received. + +11.5 ZFILE + +This packet denotes the beginning of a file transmission attempt. +ZF0, ZF1, and ZF2 may contain options. A value of 0 in each of these +bytes implies no special treatment. If options are specified to the +reciever, they override options specified to the sender with the +exception of the ZCBIN option, which overrides any other Conversion +Option. + + +11.5.1 ZF0: Conversion Option +If the receiver does not recognize the Conversion Option, an +application dependent default conversion may apply. + +ZCBIN "Binary" transfer - inhibit conversion unconditionally + + + + + +Chapter 11 rev051486 Printed 5-16-86 16 + + + + + + + +Chapter 11 rev051486 Printed 5-16-86 17 + + + +ZCNL Convert received end of line to local end of line convention. + The suported end line conventions are CR/LF (most ASCII based + operating systems except Unix and Macintosh), and NL (Unix). + Neither of these two end of line conventions violate the + permissible ASCII definitions for Carriage Return and Line + Feed/New Line. + +ZCRECOV Recover interrupted file transfer; start transfer at location + corresponding to the receiver's end of file. This option does + not apply if the source file is shorter. Files that have been + converted (e.g., ZCNL) or subject to a single ended Transport + Option cannot have their transfers recovered. + +11.5.2 ZF1: Management Option +If the receiver does not recognize the Management Option, the file +should be transferred normally. + +ZMNEW Compare the source and destination files. Transfer file if + source newer or different length + +ZMCRC Compare the source and destination files. Transfer if + different file length or CRC + +ZMAPND Append source file contents to existing destination file (if + any) + +ZMCLOB Replace existing destination file (if any) + +ZTSPARS Special processing for sparse file; each file segment is + transmitted as a separate frame, where the frames are not + necessarily contiguous. + +11.5.3 ZF2: Transport Option +If the receiver does not implement the particular transport option, +the file is copied without conversion for later processing. + +ZTLZW Lempel-Ziv compression. Transmitted data will be identical to + that produced by compress 4.0 operating on a computer with VAX + byte ordering, using 12 bit encoding. + +ZTCRYPT Encryption. An initial null terminated string identifies the + key. Details to be determined. + +ZTRLE Run Length encoding Details to be determined. + +A ZCRCW data packet follows with file name, file length, modification +date, and other information described in a later chapter. + + + + + + + +Chapter 11 rev051486 Printed 5-16-86 17 + + + + + + + +Chapter 11 rev051486 Printed 5-16-86 18 + + + +11.6 ZSKIP + +Sent by the receiver in response to ZFILE, makes the sender skip to +the next file. + +11.7 ZNAK + +Indicates last packet header was garbled. (See also ZRPOS). + +11.8 ZABORT + +Sent by receiver to terminate batch file transfers when requested by +the user. Sender initiates a ZFIN sequence.[1] + +11.9 ZFIN + +Sent by sending program to terminate a ZMODEM session. Receiver +responds with ZFIN. + +11.10 ZRPOS + +Sent by receiver to force file transfer to resume at file offset +given in ZP0...ZP3. + +11.11 ZDATA + +ZP0...ZP3 contain file offset. One or more data packets follow. + +11.12 ZEOF + +Sender reports End of File. ZP0...ZP3 contain the ending file +offset. + +11.13 ZFERR + +Error in reading or writing file, protocol equivalent to ZABORT. + +11.14 ZCRC + +Request (receiver) and response (sender) for file CRC. ZP0 and ZP1 +contain 16 bit file CRC. + + + + + + +__________ + + 1. Or ZCOMPL in case of server mode. + + + + +Chapter 11 rev051486 Printed 5-16-86 18 + + + + + + + +Chapter 11 rev051486 Printed 5-16-86 19 + + + +11.15 ZCHALLENGE + +Request to echo a random number in ZP0...ZP3 in a ZACK frame. Sent +by the receiving program to the sending program to verify that it is +connected to an operating program, and was not activated by spurious +data or a Trojan Horse message. + +11.16 ZCOMPL + +Request now completed. + +11.17 ZCAN + +This is a pseudo frame type returned by gethdr() in response to a +Cancel sequence. + +11.18 ZFREECNT + +Sending program requests a ZACK frame with ZP0...ZP3 containing the +number of free bytes on the current file system. A value of 0 +represents an indefinite amount of free space. + +11.19 ZCOMMAND + +ZCOMMAND is only sent as a binary header packet. ZP0...ZP2 contain a +unique cardinal number to differentiate this command from other +commands[2]. ZF0 contains 0 or ZCACK1. + + +A ZCRCW data packet follows, with the ASCII text command string +terminated with a NULL character. If the command is intended to be +executed by the operating system hosting the receiving program (e.g., +"shell escape"), it must have "!" as the first character. Otherwise +the command is meant to be executed by the application program which +received the command. + +If ZF0 contained ZCACK1, the receiver immediately responds with a +ZCOMPL header. Otherwise, the receiver responds with a ZCOMPL header +when the operation is completed. + +The exit status of the completed command is stored in ZP0...ZP3 (0 if +ZCACK1). A 0 exit status implies nominal completion of the command. + +If the command caused a file to be transmitted, the command sender +will see a ZRQINIT frame from the other computer attempting to send + + +__________ + + 2. Currently unused. + + + + +Chapter 11 rev051486 Printed 5-16-86 19 + + + + + + + +Chapter 11 rev051486 Printed 5-16-86 20 + + + +data. + +The sender examines ZF0 of the received ZRQINIT packet to determine +it is not an echo of its own ZRQINIT packet. It is illegal for the +sending program to command the receiving program to send a command. + + + +12. TRANSACTION EXAMPLE + +12.1 A simple file transfer + +A simple transaction, one file, no errors, no CHALLENGE, overlapped +I/O: + +Sender Receiver + +"rz\r" +ZRQINIT(0) + ZRINIT +ZFILE + ZRPOS +ZDATA data ... +ZEOF + ZRINIT +ZFIN + ZFIN +OO + + +12.2 Challenge and Command Download + + +Sender Receiver + +"rz\r" +ZRQINIT(ZCOMMAND) + ZCHALLENGE(rnd) +ZACK(same-rnd) + ZRINIT +ZCOMMAND + (Perform Command) + ZCOMPL +ZFIN + ZFIN +OO + + + + + + + + +Chapter 13 rev051486 Printed 5-16-86 20 + + + + + + + +Chapter 13 rev051486 Printed 5-16-86 21 + + + +13. ZFILE FRAME FILE INFORMATION + +ZMODEM sends the same file information with the ZFILE frame data that +YMODEM Batch sends in its block 0. + +N.B.: Only the pathname (file name) part is s required for batch +transfers. + +Pathname The pathname (conventionally, the file name) is sent as a + null terminated ASCII string. This is the filename format used + by the handle oriented MSDOS(TM) functions and C library fopen + functions. An assembly language example follows: + DB 'foo.bar',0 + No spaces are included in the pathname. Normally only the file + name stem (no directory prefix) is transmitted unless the sender + has selected YAM's f option to send the full relative pathname. + The source drive designator (A:, B:, etc.) is not sent. + + Filename Considerations: + + + File names should be translated to lower case unless the + sending system supports upper/lower case file names. This + is a convenience for users of systems (such as Unix) which + store filenames in upper and lower case. + + + The receiver should accommodate file names in lower and + upper case. + + + The rb(1) program on Unix systems normally translates the + filename to lower case unless one or more letters in the + filename are already in lower case. + + + When transmitting files between different operating + systems, file names must be acceptable to both the sender + and receiving operating systems. + + If directories are included, they are delimited by /; i.e., + "subdir/foo" is acceptable, "subdir\foo" is not. + +Length The file length and each of the succeeding fields are + optional.[1] The length field is stored as a decimal string + counting the number of data bytes in the file. + + With ZMODEM, the receiver uses the file length only for display + (progress reporting) purposes; the actual length is determined + + +__________ + + 1. Fields may not be skipped. + + + + +Chapter 13 rev051486 Printed 5-16-86 21 + + + + + + + +Chapter 13 rev051486 Printed 5-16-86 22 + + + + by the data transfer. + +Modification Date A single space separates the modification date from + the file length. + + The mod date is optional, and the filename and length may be + sent without requiring the mod date to be sent. + + The mod date is sent as an octal number giving the time the + contents of the file were last changed measured in seconds from + Jan 1 1970 Universal Coordinated Time (GMT). A date of 0 + implies the modification date is unknown and should be left as + the date the file is received. + + This standard format was chosen to eliminate ambiguities arising + from transfers between different time zones. + + Two Microsoft blunders complicate the use of modification dates + in file transfers with MSDOS(TM) systems. The first is the lack + of timezone standardization in MS-DOS. A file's creation time + can not be known unless the timezone of the system that wrote + the file[2] is known. Unix solved this problem (for planet + Earth, anyway) by stamping files with Universal Time (GMT). + Microsoft would have to include the timezone of origin in the + directory entries, but does not. Professional-YAM gets around + this problem by using the z parameter which is set to the number + of minutes local time lags GMT. For files known to originate + from a different timezone, the -zT option may be used to specify + T as the timezone for an individual file transfer. + + The second problem is the lack of a separate file creation date + in DOS. Since some backup schemes used with DOS rely on the + file creation date to select files to be copied to the archive, + back-dating the file modification date could interfere with the + safety of the transferred files. For this reason, + Professional-YAM does not modify the date of received files with + the header information unless the d parameter is non zero. + + +Mode A single space separates the file mode from the modification + date. The file mode is stored as an octal string. Unless the + file originated from a Unix system, the file mode is set to 0. + rb(1) checks the file mode for the 0x8000 bit which indicates a + Unix type regular file. Files with the 0x8000 bit set are + assumed to have been sent from another Unix (or similar) system + + +__________ + + 2. Not necessarily that of the transmitting system! + + + + +Chapter 13 rev051486 Printed 5-16-86 22 + + + + + + + +Chapter 13 rev051486 Printed 5-16-86 23 + + + + which uses the same file conventions. Such files are not + translated in any way. + + +Serial Number A single space separates the serial number from the + file mode. The serial number of the transmitting program is + stored as an octal string. Programs which do not have a serial + number should omit this field, or set it to 0. The receiver's + use of this field is optional. + +The file information is terminated by a null. If only the pathname +is sent, the pathname will be terminated by two nulls. The length of +the file information packet, including the trailing null, must not +exceed 1024 bytes; a typical length is less than 64 bytes. + + +14. PERFORMANCE RESULTS + +14.1 Throughput + +Between two single task PC-XT computrers, on a Telenet link through +the local Telenet, SuperKermit gave 72 ch/sec throughput at 1200 +baud. YMODEM-k yielded 85 chars/sec, and ZMODEM provided 113 chat +sec. ZMODEM was not measured, but would have given much less. + +14.2 Error Recovery + +Some tests of ZMODEM protocol performance have been made. A PC-AT +with SCO SYS V Xenix or DOS 3.1 was connected to a PC with DOS 2.1 +either directly at 9600 bps or with unbuffered dial-up 1200 bps +modems. The ZMODEM software was configured to use 1024 byte packet +lengths above 2400 bps, 256 otherwise. + +Because no time delays are necessary in normal file transfers, per +file negotiations are much faster than with YMODEM, the only observed +impidiment being the time required by the program(s) to update +logging files. + +During a file transfer, a short line hit seen by the receiver usually +induces a CRC error. The interrupt packet is usually seen by the +sender before the next packet is sent, and the resultant loss of data +throughput averages about half a packet. At 1200 bps this is would +be about .75 second lost per hit. At 10-5 error rate, this would +degrade throughput by about 9 per cent. The throughput degradation +increases with the channel delay, as the packets in transit through +the channel are discarded on error. + +A longer noise burst that affects both the receiver and the sender's +reception of the interrupt packet usually causes the sender to remain +silent until the receiver times out in 10 seconds. If the round trip +channel delay exceeds the receiver's 10 second timeout, recovery from + + + +Chapter 14 rev051486 Printed 5-16-86 23 + + + + + + + +Chapter 14 rev051486 Printed 5-16-86 24 + + + +this type of error may become difficult. + +Noise affecting only the sender is usually ignored, with one common +exception. Spurious XOFF characters generated by noise stop the +sender until the receiver times out and sends an interrupt packet +which concludes with an XON. + +In summation, ZMODEM performance in the presence of errors resembles +that of X.PC and SuperKermit. Short bursts cause minimuml data loss. +Long bursts (such as pulse dialing noises) often require a timeout +error to restore the flow of data. + + +15. PACKET SWITCHED NETWORK CONSIDERATIONS + +Flow control is necessary for printing messages and directories, and +for streaming file transfer protocols including Kermit Sliding +Windows and ZMODEM. A non transparent flow control is incompatible +with XMODEM and YMODEM transfers. XMODEM and YMODEM protocols +require complete transparency of all 256 8 bit codes to operate +properly. + +The most desireable flow control (when X.25 or hardware CTS is +unavailable) does not "eat" any characters at all. When the PAD's +buffer almost fills up, an XOFF should be emitted. When the buffer +is no longer nearly full, send an XON. Otherwise, the network should +neither generate nor eat XON or XOFF control characters. + +On Telenet, this can be met by setting CCIT X3 5:1 and 12:0 at both +ends of the network. For best throughput, parameter 64 (advance ACK) +should be set to something like 4. Packets should be sent when the +packet is a full 128 bytes, or after a moderate delay (3:0,4:10,6:0). + +For YMODEM, PAD buffering should guarantee that a minimum of 1040 +characters can be sent in a burst without loss of data or generation +of flow control characters. Failure to provide this buffering will +generate excessive retries with YMODEM. + + Figure 4. Flow Control Compatibility + + Connectivity Interactive XMODEM KERMIT ZMODEM + +Direct Connection YES YES YES YES +Network, no flow control NO YES (1) (1) +Network, transparent f.c. YES YES YES YES +Network, semi-transparent f.c. YES NO YES YES +Network, 7 bit YES NO YES(2) NO(3) + +(1) Cannot operate in streaming mode. Kermit is very slow because of +96 byte max packet size. ZMODEM can adjust burst length to maximum +for faster transfers. + + + +Chapter 15 rev051486 Printed 5-16-86 24 + + + + + + + +Chapter 15 rev051486 Printed 5-16-86 25 + + + +(2) Parity bits must be encoded, slowing binary transfers. + +(3) Extension possible for encoding data to 7 bits. + + + +16. PERFORMANCE COMPARISION TABLES + + +"Round Trip Delay Time" includes the time for the last byte in a +packet to propagate through the operating systems and network to the +receiver, plus the time for the receiver's response to that packet to +propogate back to the sender. + +The figures shown below are calculated for round trip delay times of +40 milliseconds and 5 seconds. Shift registers in the two computers +and a pair of 212 modems generate a round trip delay time on the +order of 40 milliseconds. Operation with busy timesharing computers +and networks can easily generate round trip delays of five seconds. +Because the round trip delays cause visible interruptions of data +transfer when using XMODEM protocol, the subjective effect of these +delays is greatly exaggerated, especially when the user is paying for +connect time. + +A 102400 byte binary file with randomly distributed codes is sent at +1200 bps 8 data bits, 1 stop bit. The calculations assume no +transmission errors. For each of the protocols, only the per file +functions are considered. Processor and I/O overhead are not +included. YM-k refers to YMODEM with 1024 byte packets. YM-g refers +to the YMODEM "g" option. ZMODEM uses 256 byte packets for this +example. SuperKermit uses maximum packet size, 8 bit transparent +transmission, no run length compression. + +For comparison, a straight "dump" of the file contents with no file +management or error checking takes 853 seconds. + + Figure 5. Protocol Overhead Information + + Protocol XMODEM YM-k YM-g ZMODEM S-Kermit + +Protocol Round Trips 803 103 5 5 5 +Trip Time at 40ms 32s 4s 0 0 0 +Trip Time at 5s 4015s 515s 25s 25s 25 + +Overhead Characters 4803 603 503 3600 38280 + +Transfer Time at 0s 893s 858s 857s 883s 1172s +Transfer Time at 40ms 925s 862s 857s 883s 1172s +Transfer Time at 5s 5761s 1373s 882s 918s 1197s + + + + + +Chapter 16 rev051486 Printed 5-16-86 25 + + + + + + + +Chapter 16 rev051486 Printed 5-16-86 26 + + + + Figure 6. Transmission Time Comparision + (5 Second Round Trip) + +************************************************** XMODEM +************ YMODEM-K +********** SuperKermit (Sliding Windows) +******* YMODEM-G +******* ZMODEM + + Figure 7. Y/ZMODEM Header Information usage + + + Program Batch Length Date Mode S/N YMODEM-g ZMODEM + Unix rb/sb yes yes yes yes no sb only no + Unix rz/sz yes yes yes yes no sz only yes + VMS rb/sb yes yes no no no no no + Pro-YAM yes yes yes no yes yes yes + CP/M YAM yes no no no no no no + KMD/IMP yes yes- no no no no no + MEX no no no no no no no + + +17. MORE INFORMATION + +More information may be obtained by calling Telegodzilla at +503-621-3746. + +UUCP sites can obtain the nroff/troff source to this file with + uucp omen!/usr/caf/public/zmodem.mm /tmp +A continually updated list of available files is stored in +/usr/spool/uucppublic/FILES. + +The following L.sys line calls site "omen" yia UUCP. Telegodzilla +uses Pro-YAM in host operation. + +In response to "Name Please:" uucico gives the Pro-YAM "link" command +as a user name. The password (Giznoid) controls access to the Xenix +system connected to the IBM PC's other serial port. Communications +between Pro-YAM and Xenix use 9600 bps; YAM converts this to the +caller's speed. + +Finally, the calling uucico logs in as uucp. + + omen Any ACU 1200 1-503-621-3746 e:--e: link d: Giznoid n:--n: uucp + + + + + + + + + + +Chapter 18 rev051486 Printed 5-16-86 26 + + + + + + + +Chapter 18 rev051486 Printed 5-16-86 27 + + + +18. ZMODEM PROGRAMS + +A demonstration version of Professional-YAM is available as +YAMDEMO.ARC on TeleGodzilla.. This file must be unpacked with the +"ARC" program, version 5 or later. A copy of ARC is available as +"ARC.EXE" or "ARC510.COM" on TeleGodzilla. + + +This may be used to test ZMODEM and YMODEM implementations. A +flash-up tree structured help file and processor are provided in +YAMHELP.LQR. + + + +19. YMODEM PROGRAMS + +Unix programs supporting the YMODEM protocol are available on +Telegodzilla in the "upgrade" subdirectory as RBSB.SHQ (a SQueezed +shell archive). Most Unix like systems are supported, including V7, +Sys III, 4.2 BSD, SYS V, Idris, Coherent, and Regulus. + +A version for VAX-VMS is available in VRBSB.SHQ, in the same +directory. + +Irv Hoff has added YMODEM 1k packets and YMODEM batch transfers to +the KMD and IMP series programs, which replace the XMODEM and +MODEM7/MDM7xx series respectively. Overlays are available for a wide +variety of CP/M systems. + +Many other programs, including MEX and MEX-PC also support some of +the YMODEM extensions. + +Questions about YMODEM, the Professional-YAM communications program, +and requests for evaluation copies may be directed to: + + Chuck Forsberg + Omen Technology Inc + 17505-V Sauvie Island Road + Portland Oregon 97231 + Voice: 503-621-3406 + Modem (Telegodzilla): 503-621-3746 + Usenet: ...!tektronix!reed!omen!caf + Compuserve: 70715,131 + Source: TCE022 + + Yours very truly, + + + + + + + + +Chapter 19 rev051486 Printed 5-16-86 27 + + + + + + + + + + + + CONTENTS + + + 1. INTENDED AUDIENCE................................................ 2 + + 2. ACKNOWLEDGMENTS.................................................. 2 + + 3. RELATED DOCUMENTS................................................ 2 + + 4. ROSETTA STONE.................................................... 2 + + 5. WHY DEVELOP ZMODEM?.............................................. 3 + + 6. ZMODEM Protocol Design Criteria.................................. 5 + 6.1 Ease of Use............................................... 5 + 6.2 Throughput................................................ 5 + 6.3 Integrity and Robustness.................................. 6 + 6.4 Ease of Implementation.................................... 6 + + 7. ZMODEM BASICS.................................................... 6 + 7.1 Packetization............................................. 7 + 7.2 Link Escape Encoding...................................... 7 + 7.3 Header Packet Information................................. 8 + 7.4 Binary Header Packet...................................... 9 + 7.5 HEX Header Packet......................................... 9 + 7.6 Binary Data Packets....................................... 10 + 7.7 ASCII Encoded Data Packet................................. 10 + + 8. PROTOCOL TRANSACTION OVERVIEW.................................... 10 + 8.1 Session Cancel Packet..................................... 13 + + 9. ZMODEM STREAMING TECHNIQUES...................................... 14 + 9.1 Full Streaming with Sampling.............................. 14 + 9.2 Full Streaming with Interrupt............................. 14 + 9.3 Full Streaming with a Sliding Window...................... 15 + 9.4 No Streaming.............................................. 15 + +10. ATTENTION SEQUENCE............................................... 15 + +11. PACKET/FRAME TYPES............................................... 15 + 11.1 ZRQINIT................................................... 16 + 11.2 ZRINIT.................................................... 16 + 11.3 ZSINIT.................................................... 16 + 11.4 ZACK...................................................... 16 + 11.5 ZFILE..................................................... 16 + 11.6 ZSKIP..................................................... 18 + 11.7 ZNAK...................................................... 18 + 11.8 ZABORT.................................................... 18 + 11.9 ZFIN...................................................... 18 + 11.10 ZRPOS..................................................... 18 + 11.11 ZDATA..................................................... 18 + + + + - i - + + + + + + + + + + + + 11.12 ZEOF...................................................... 18 + 11.13 ZFERR..................................................... 18 + 11.14 ZCRC...................................................... 18 + 11.15 ZCHALLENGE................................................ 19 + 11.16 ZCOMPL.................................................... 19 + 11.17 ZCAN...................................................... 19 + 11.18 ZFREECNT.................................................. 19 + 11.19 ZCOMMAND.................................................. 19 + +12. TRANSACTION EXAMPLE.............................................. 20 + 12.1 A simple file transfer.................................... 20 + 12.2 Challenge and Command Download............................ 20 + +13. ZFILE FRAME FILE INFORMATION..................................... 21 + +14. PERFORMANCE RESULTS.............................................. 23 + 14.1 Throughput................................................ 23 + 14.2 Error Recovery............................................ 23 + +15. PACKET SWITCHED NETWORK CONSIDERATIONS........................... 24 + +16. PERFORMANCE COMPARISION TABLES................................... 25 + +17. MORE INFORMATION................................................. 26 + +18. ZMODEM PROGRAMS.................................................. 27 + +19. YMODEM PROGRAMS.................................................. 27 + + + + + + + + + + + + + + + + + + + + + + + + + + + - ii - + + + + + + + + + + + + + + + LIST OF FIGURES + + +Figure 1. Order of Bytes in Header Packet............................ 8 + +Figure 2. Binary Header Packet....................................... 9 + +Figure 3. HEX Header Packet.......................................... 10 + +Figure 4. Flow Control Compatibility................................. 24 + +Figure 5. Protocol Overhead Information.............................. 25 + +Figure 6. Transmission Time Comparision.............................. 26 + +Figure 7. Y/ZMODEM Header Information usage.......................... 26 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - iii - + + + + + + + + + + The ZMODEM Asynchronous Inter Application File Transfer Protocol + + Chuck Forsberg + + Omen Technology Inc + + + ABSTRACT + + + +The ZMODEM file transfer protocol greatly simplifies file transfers +compared to XMODEM. In addition to supporting a transparent user +interface, ZMODEM provides Personal Computer and other users an efficient, +accurate, robust file transfer method. + +ZMODEM provides especially efficient file transfers with timesharing +systems, satellite relays, and wide area packet switched networks. A +choice of buffering and windowing modes allow ZMODEM to operate +efficiently on systems that cannot support some other streaming protocols. + +ZMODEM provides advanced file management features including AutoDownload, +remote file compare, aborted transfer recovery, selective file transfers, +and security verified command downloading. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +sא[ E 0bsu@;w`R00 +Xv{u P +eQBm +Ї0h+0  [ 0 s0O0y8`Y80 OPcX 0sPPh O;>P]İp 0jǠ> t F (P H%upNj&k` Ǎ@TհʠAEP]  r6E%wrpp A$@X@rI&p o@%Fs + + f^ s +F + `pgt Y3),`ƠH'0%yr+i0P  8l(Ҁ?iB[i^9Dgjɖ,9or