📄 zmdm.c
字号:
/******************************************************************************//* Project : Unite! File : zmodem general Version : 1.02 *//* *//* (C) Mattheij Computer Service 1994 *//* *//* contact us through (in order of preference) *//* *//* email: jacquesm@hacktic.nl *//* mail: MCS *//* Prinses Beatrixlaan 535 *//* 2284 AT RIJSWIJK *//* The Netherlands *//* voice phone: 31+070-3936926 *//******************************************************************************//* * zmodem primitives and other code common to zmtx and zmrx */#include <stdio.h>#undef _KERNEL#include <sys/termios.h>#include <errno.h>#define _KERNEL#include <signal.h>#include <unistd.h>#include <string.h>#ifdef UNITE#include <sys/select.h>#endif#ifdef SUNOS4#include <sys/types.h>#endif#include <sys/time.h>#include "zmodem.h"#define ZMDM#include "zmdm.h"#include "crctab.h"#include <pmon.h>int port_fd;FILE *port_fp;int receive_32_bit_data;int raw_trace;int want_fcs_32 = TRUE;long ack_file_pos; /* file position used in acknowledgement of correctly */ /* received data subpackets */extern FILE *logfp;#define XXX_SKIP_CRC 1 /* XXX: Skip CRC check at the moment */void fd_init(FILE *fp){ port_fd = fileno(fp); port_fp = fp;}/* * read bytes as long as rdchk indicates that * more data is available. */void rx_purge(void){ struct timeval t; fd_set f; unsigned char c; t.tv_sec = 0; t.tv_usec = 0; FD_ZERO(&f); FD_SET(port_fd, &f); while (select(port_fd, &f, NULL, NULL, &t)) { read(port_fd, &c, 1); }}int last_sent = -1;/* * transmit a character. * this is the raw modem interface */void tx_raw(int c){#ifdef DEBUG if (raw_trace) { fprintf(logfp, "%02x ", c); }#endif last_sent = c & 0x7f;#if 0 putchar(c);#else { char tmp; tmp = c; write(port_fd, &tmp, 1); }#endif}/* * transmit a character ZDLE escaped */void tx_esc(int c){ tx_raw(ZDLE); /* * exclusive or; not an or so ZDLE becomes ZDLEE */ tx_raw(c ^ 0x40);}/* * transmit a character; ZDLE escaping if appropriate */void tx(unsigned char c){ switch (c) { case ZDLE: tx_esc(c); return; break; case 0x8d: case 0x0d: if (escape_all_control_characters && last_sent == '@') { tx_esc(c); return; } break; case 0x10: case 0x90: case 0x11: case 0x91: case 0x13: case 0x93: tx_esc(c); return; break; default: if (escape_all_control_characters && (c & 0x60) == 0) { tx_esc(c); return; } break; } /* * anything that ends here is so normal we might as well transmit it. */ tx_raw((int) c);}/* * send the bytes accumulated in the output buffer. */void tx_flush(void){ fflush(port_fp);}/* * transmit a hex header. * these routines use tx_raw because we're sure that all the * characters are not to be escaped. */void tx_nibble(int n){ n &= 0x0f; if (n < 10) { n += '0'; } else { n += 'a' - 10; } tx_raw(n);}void tx_hex(int h){ tx_nibble(h >> 4); tx_nibble(h);}void tx_hex_header(unsigned char *p){ int i; unsigned short int crc;#ifdef DEBUG fprintf(logfp, "* tx_hex_header *\n ");#endif tx_raw(ZPAD); tx_raw(ZPAD); tx_raw(ZDLE); if (use_variable_headers) { tx_raw(ZVHEX); tx_hex(HDRLEN); } else { tx_raw(ZHEX); } /* * initialise the crc */ crc = 0; /* * transmit the header */ for (i = 0; i < HDRLEN; i++) { tx_hex(*p); crc = UPDCRC16(*p, crc); p++; } /* * update the crc as though it were zero */ crc = UPDCRC16(0, crc); crc = UPDCRC16(0, crc); /* transmit the crc */ tx_hex(crc >> 8); tx_hex(crc); /* * end of line sequence */ tx_raw(0x0d); tx_raw(0x0a); tx_raw(XON); tx_flush();#ifdef DEBUG fprintf(logfp, "\n");#endif}/* * Send ZMODEM binary header hdr */void tx_bin32_header(unsigned char *p){ int i; unsigned long crc;#ifdef DEBUG fprintf(logfp, "tx binary header 32 bits crc\n"); raw_trace = 1;#endif tx_raw(ZPAD); tx_raw(ZPAD); tx_raw(ZDLE); if (use_variable_headers) { tx_raw(ZVBIN32); tx(HDRLEN); } else { tx_raw(ZBIN32); } crc = 0xffffffffL; for (i = 0; i < HDRLEN; i++) { crc = UPDCRC32(*p, crc); tx(*p++); } crc = ~crc; tx(crc); tx(crc >> 8); tx(crc >> 16); tx(crc >> 24);}void tx_bin16_header(unsigned char *p){ int i; unsigned int crc;#ifdef DEBUG fprintf(logfp, "tx binary header 16 bits crc\n");#endif tx_raw(ZPAD); tx_raw(ZPAD); tx_raw(ZDLE); if (use_variable_headers) { tx_raw(ZVBIN); tx(HDRLEN); } else { tx_raw(ZBIN); } crc = 0; for (i = 0; i < HDRLEN; i++) { crc = UPDCRC16(*p, crc); tx(*p++); } crc = UPDCRC16(0, crc); crc = UPDCRC16(0, crc); tx(crc >> 8); tx(crc);}/* * transmit a header using either hex 16 bit crc or binary 32 bit crc * depending on the receivers capabilities * we dont bother with variable length headers. I dont really see their * advantage and they would clutter the code unneccesarily */void tx_header(unsigned char *p){ if (can_fcs_32) { if (want_fcs_32) { tx_bin32_header(p); } else { tx_bin16_header(p); } } else { tx_hex_header(p); }}/* * data subpacket transmission */void tx_32_data(int sub_frame_type, unsigned char *p, int l){ unsigned long crc;#ifdef DEBUG fprintf(logfp, "tx_32_data\n");#endif crc = 0xffffffffl; while (l > 0) { crc = UPDCRC32(*p, crc); tx(*p++); l--; } crc = UPDCRC32(sub_frame_type, crc); tx_raw(ZDLE); tx_raw(sub_frame_type); crc = ~crc; tx((int) (crc) & 0xff); tx((int) (crc >> 8) & 0xff); tx((int) (crc >> 16) & 0xff); tx((int) (crc >> 24) & 0xff);}void tx_16_data(int sub_frame_type, unsigned char *p, int l){ unsigned short crc;#ifdef DEBUG fprintf(logfp, "tx_16_data\n");#endif crc = 0; while (l > 0) { crc = UPDCRC16(*p, crc); tx(*p++); l--; } crc = UPDCRC16(sub_frame_type, crc); tx_raw(ZDLE); tx_raw(sub_frame_type); crc = UPDCRC16(0, crc); crc = UPDCRC16(0, crc); tx(crc >> 8); tx(crc);}/* * send a data subpacket using crc 16 or crc 32 as desired by the receiver */void tx_data(int sub_frame_type, unsigned char *p, int l){ if (want_fcs_32 && can_fcs_32) { tx_32_data(sub_frame_type, p, l); } else { tx_16_data(sub_frame_type, p, l); } if (sub_frame_type == ZCRCW) { tx_raw(XON); } tx_flush();}void tx_pos_header(int type, long pos){ char header[5]; header[0] = type; header[ZP0] = pos & 0xff; header[ZP1] = (pos >> 8) & 0xff; header[ZP2] = (pos >> 16) & 0xff; header[ZP3] = (pos >> 24) & 0xff; tx_hex_header(header);}void tx_znak(){#ifdef DEBUG fprintf(logfp, "tx_znak\n");#endif tx_pos_header(ZNAK, ack_file_pos);}void tx_zskip(){ tx_pos_header(ZSKIP, 0L);}/* * receive any style header within timeout milliseconds */void alrm(int a){ signal(SIGALRM, SIG_IGN);}int rx_poll(){ struct timeval t; fd_set f; t.tv_sec = 0; t.tv_usec = 0; FD_ZERO(&f); FD_SET(port_fd, &f); if (select(port_fd, &f, NULL, NULL, &t)) { return 1; } return 0;}unsigned char inputbuffer[1024];int n_in_inputbuffer = 0;int inputbuffer_index;/* * rx_raw ; receive a single byte from the line. * reads as many are available and then processes them one at a time * check the data stream for 5 consecutive CAN characters; * and if you see them abort. this saves a lot of clutter in * the rest of the code; even though it is a very strange place * for an exit. (but that was wat session abort was all about.) */int rx_raw(int to){ unsigned char c; static int n_cans = 0; if (n_in_inputbuffer == 0) { /* * change the timeout into seconds; minimum is 1 */#if 0 to /= 1000; if (to == 0) { to++; } /* * setup an alarm in case io takes too long */ signal(SIGALRM, alrm); to /= 1000; if (to == 0) { to = 2; } alarm(to);#endif n_in_inputbuffer = read(port_fd, inputbuffer, 1); /* was 1024 */#if 0 if (n_in_inputbuffer <= 0) { n_in_inputbuffer = 0; }#endif /* * cancel the alarm in case it did not go off yet */#if 0 signal(SIGALRM, SIG_IGN);#endif if (n_in_inputbuffer < 0 && (errno != 0 && errno != EINTR)) { fprintf(logfp, "zmdm : fatal error reading device\n"); return(1); } if (n_in_inputbuffer == 0) { return TIMEOUT; } inputbuffer_index = 0; } c = inputbuffer[inputbuffer_index++]; n_in_inputbuffer--; if (c == CAN) { n_cans++; if (n_cans == 5) {#if 0 /* * the other side is serious about this. just shut up; * clean up and exit. */ cleanup();#endif return(CAN); } } else { n_cans = 0; } return c;}/* * rx; receive a single byte undoing any escaping at the * sending site. this bit looks like a mess. sorry for that * but there seems to be no other way without incurring a lot * of overhead. at least like this the path for a normal character * is relatively short. */int rx(int to){ int c; /* * outer loop for ever so for sure something valid * will come in; a timeout will occur or a session abort * will be received. */ while (TRUE) { /* * fake do loop so we may continue * in case a character should be dropped. */ do { c = rx_raw(to); if (c == TIMEOUT) { return c; } switch (c) { case ZDLE: break; case 0x11: case 0x91: case 0x13: case 0x93: continue; break; default: /* * if all control characters should be escaped and * this one wasnt then its spurious and should be dropped. */ if (escape_all_control_characters && (c & 0x60) == 0) { continue; } /* * normal character; return it.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -