📄 fio.c
字号:
#ifndef lintstatic char *sccsid = "@(#)fio.c 4.1 (ULTRIX) 7/2/90";#endif lint/************************************************************************ * * * Copyright (c) 1984 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//* * flow control protocol. * * This protocol relies on flow control of the data stream. * It is meant for working over links that can (almost) be * guaranteed to be errorfree, specifically X.25/PAD links. * A sumcheck is carried out over a whole file only. If a * transport fails the receiver can request retransmission(s). * This protocol uses a 7-bit datapath only, so it can be * used on links that are not 8-bit transparent. * * When using this protocol with an X.25 PAD: * Although this protocol uses no control chars except CR, * control chars NULL and ^P are used before this protocol * is started; since ^P is the default char for accessing * PAD X.28 command mode, be sure to disable that access * (PAD par 1). Also make sure both flow control pars * (5 and 12) are set. The CR used in this proto is meant * to trigger packet transmission, hence par 3 should be * set to 2; a good value for the Idle Timer (par 4) is 10. * All other pars should be set to 0. * * Normally a calling site will take care of setting the * local PAD pars via an X.28 command and those of the remote * PAD via an X.29 command, unless the remote site has a * special channel assigned for this protocol with the proper * par settings. * * Additional comments for hosts with direct X.25 access: * - the global variable IsTcpIp, when set, excludes ioctl's, * so the same binary can run on X.25 and non-X.25 hosts; * - reads are done in small chunks, which can be smaller than * the packet size; your X.25 driver must support that. * * * Author: * Piet Beertema, CWI, Amsterdam, Sep 1984 * Modified for X.25 hosts: * Robert Elz, Melbourne Univ, Mar 1985 */#include "uucp.h"#include <sys/types.h>#include <sys/timeb.h>#include <signal.h>#ifdef USG#include <termio.h>#else !USG#include <sgtty.h>#endif !USG#include <setjmp.h>#define FIBUFSIZ 256 /* for X.25 interfaces: set equal to packet size, * but see comment above */#define FOBUFSIZ 1024 /* for X.25 interfaces: set equal to packet size; * otherwise make as large as feasible to reduce * number of write system calls */#ifndef MAXMSGLEN#define MAXMSGLEN BUFSIZ#endif MAXMSGLEN#ifdef TCP /* Fix083 */extern int IsTcpIp;#endif TCP /* Fix083 */static int fchksum;static jmp_buf Ffailbuf;staticfalarm(){ signal(SIGALRM, falarm); longjmp(Ffailbuf, 1);}static void (*fsig)();#ifndef USG#define TCGETA TIOCGETP#define TCSETA TIOCSETP#define termio sgttyb#endif USGfturnon(){ int ret; struct termio ttbuf;#ifdef TCP /* Fix083 */ if (!IsTcpIp) {#endif TCP /* Fix083 */ ioctl(Ifn, TCGETA, &ttbuf);#ifdef USG ttbuf.c_iflag = IXOFF|IXON|ISTRIP; ttbuf.c_cc[VMIN] = FIBUFSIZ > 64 ? 64 : FIBUFSIZ; ttbuf.c_cc[VTIME] = 5;#else !USG ttbuf.sg_flags = ANYP|CBREAK|TANDEM;#endif USG ret = ioctl(Ifn, TCSETA, &ttbuf); ASSERT(ret >= 0, "STTY FAILED", "", ret);#ifdef TCP /* Fix083 */ }#endif TCP /* Fix083 */ fsig = signal(SIGALRM, falarm); /* give the other side time to perform its ioctl; * otherwise it may flush out the first data this * side is about to send. */ sleep(2); return SUCCESS;}fturnoff(){ (void) signal(SIGALRM, fsig); return SUCCESS;}fwrmsg(type, str, fn)register char *str;int fn;char type;{ register char *s; char bufr[MAXMSGLEN]; s = bufr; *s++ = type; while (*str) *s++ = *str++; if (*(s-1) == '\n') s--; *s++ = '\r'; *s = 0; (void) write(fn, bufr, s - bufr); return SUCCESS;}frdmsg(str, fn)register char *str;register int fn;{ register char *smax; if (setjmp(Ffailbuf)) return FAIL; smax = str + MAXMSGLEN - 1; (void) alarm(2*MAXMSGTIME); for (;;) { if (read(fn, str, 1) <= 0) goto msgerr; *str &= 0177; if (*str == '\r') break; if (*str < ' ') { continue; } if (str++ >= smax) goto msgerr; } *str = '\0'; (void) alarm(0); return SUCCESS;msgerr: (void) alarm(0); return FAIL;}fwrdata(fp1, fn)FILE *fp1;int fn;{ register int alen, ret; char ack, ibuf[MAXMSGLEN]; int flen, mil, retries = 0; long abytes, fbytes; struct timeb t1, t2; ret = FAIL;retry: fchksum = 0xffff; abytes = fbytes = 0L; ack = '\0';#ifdef USG time(&t1.time); t1.millitm = 0;#else !USG ftime(&t1);#endif !USG do { alen = fwrblk(fn, fp1, &flen); fbytes += flen; if (alen <= 0) { abytes -= alen; goto acct; } abytes += alen; } while (!feof(fp1) && !ferror(fp1)); DEBUG(8, "\nchecksum: %04x\n", fchksum); if (frdmsg(ibuf, fn) != FAIL) { if ((ack = ibuf[0]) == 'G') ret = SUCCESS; DEBUG(4, "ack - '%c'\n", ack); }acct:#ifdef USG time(&t2.time); t2.millitm = 0;#else !USG ftime(&t2);#endif !USG t2.time -= t1.time; mil = t2.millitm - t1.millitm; if (mil < 0) { --t2.time; mil += 1000; } sprintf(ibuf, ret == SUCCESS ? "sent data %ld bytes %ld.%02d secs" : "send failed after %ld bytes %ld.%02d secs", fbytes, (long)t2.time, mil / 10); sysacct(abytes, (time_t)(t2.time + (mil >= 250 ? 1 : 0))); if (retries > 0) sprintf(&ibuf[strlen(ibuf)], ", retry #%d", retries); DEBUG(1, "%s\n", ibuf); syslog(ibuf); if (ack == 'R') { DEBUG(4, "RETRY:\n", 0); fseek(fp1, 0L, 0); retries++; goto retry; }#ifdef SYSACCT if (ret == FAIL) sysaccf(NULL); /* force accounting */#endif SYSACCT return ret;}/* max. attempts to retransmit a file: */#define MAXRETRIES (fbytes < 10000L ? 2 : 1)frddata(fn, fp2)register int fn;register FILE *fp2;{ register int flen; register char eof; char ibuf[FIBUFSIZ]; int ret, mil, retries = 0; long alen, abytes, fbytes; struct timeb t1, t2; ret = FAIL;retry: fchksum = 0xffff; abytes = fbytes = 0L;#ifdef USG time(&t1.time); t1.millitm = 0;#else !USG ftime(&t1);#endif !USG do { flen = frdblk(ibuf, fn, &alen); abytes += alen; if (flen < 0) goto acct; if (eof = flen > FIBUFSIZ) flen -= FIBUFSIZ + 1; fbytes += flen; if (fwrite(ibuf, sizeof (char), flen, fp2) != flen) goto acct; } while (!eof); ret = SUCCESS;acct:#ifdef USG time(&t2.time); t2.millitm = 0;#else !USG ftime(&t2);#endif !USG t2.time -= t1.time; mil = t2.millitm - t1.millitm; if (mil < 0) { --t2.time; mil += 1000; } sprintf(ibuf, ret == SUCCESS ? "received data %ld bytes %ld.%02d secs" : "receive failed after %ld bytes %ld.%02d secs", fbytes, (long)t2.time, mil / 10); sysacct(abytes, (time_t)(t2.time + (mil >= 250 ? 1 : 0))); DEBUG(1, "%s\n", ibuf); syslog(ibuf); if (ret == FAIL) { if (retries++ < MAXRETRIES) { DEBUG(8, "send ack: 'R'\n", 0); fwrmsg('R', "", fn); fseek(fp2, 0L, 0); DEBUG(4, "RETRY:\n", 0); goto retry; } DEBUG(8, "send ack: 'Q'\n", 0); fwrmsg('Q', "", fn);#ifdef SYSACCT sysaccf(NULL); /* force accounting */#endif SYSACCT } else { DEBUG(8, "send ack: 'G'\n", 0); fwrmsg('G', "", fn); } return ret;}staticfrdbuf(blk, len, fn)register char *blk;register int len;register int fn;{ static int ret = FIBUFSIZ / 2; if (setjmp(Ffailbuf)) return FAIL; (void) alarm(MAXMSGTIME); ret = read(fn, blk, len); alarm(0); return ret <= 0 ? FAIL : ret;}/* call ultouch every TC calls to either frdblk or fwrblk */#define TC 20static int tc = TC;/* Byte conversion: * * from pre to * 000-037 172 100-137 * 040-171 040-171 * 172-177 173 072-077 * 200-237 174 100-137 * 240-371 175 040-171 * 372-377 176 072-077 */staticfwrblk(fn, fp, lenp)int fn;register FILE *fp;int *lenp;{ register char *op; register int c, sum, nl, len; char obuf[FOBUFSIZ + 8]; int ret; /* call ultouch occasionally */ if (--tc < 0) { tc = TC; ultouch(); } op = obuf; nl = len = 0; sum = fchksum; while ((c = getc(fp)) != EOF) { len++; if (sum & 0x8000) { sum <<= 1; sum++; } else sum <<= 1; sum += c; sum &= 0xffff; if (c & 0200) { c &= 0177; if (c < 040) { *op++ = '\174'; *op++ = c + 0100; } else if (c <= 0171) { *op++ = '\175'; *op++ = c; } else { *op++ = '\176'; *op++ = c - 0100; } nl += 2; } else { if (c < 040) { *op++ = '\172'; *op++ = c + 0100; nl += 2; } else if (c <= 0171) { *op++ = c; nl++; } else { *op++ = '\173'; *op++ = c - 0100; nl += 2; } } if (nl >= FOBUFSIZ - 1) { /* * peek at next char, see if it will fit */ c = getc(fp); if (c == EOF) break; (void) ungetc(c, fp); if (nl >= FOBUFSIZ || c < 040 || c > 0171) goto writeit; } } /* * At EOF - append checksum, there is space for it... */ sprintf(op, "\176\176%04x\r", sum); nl += strlen(op);writeit: *lenp = len; fchksum = sum; DEBUG(8, "%d/", len); DEBUG(8, "%d ", nl); ret = write(fn, obuf, nl); return ret == nl ? nl : ret < 0 ? 0 : -ret;}staticfrdblk(ip, fn, rlen)register char *ip;int fn;long *rlen;{ register char *op, c; register int sum, len, nl; char buf[5], *erbp = ip; int i; static char special = 0; /* call ultouch occasionally */ if (--tc < 0) { tc = TC; ultouch(); } if ((len = frdbuf(ip, FIBUFSIZ, fn)) == FAIL) { *rlen = 0; goto dcorr; } *rlen = len; DEBUG(8, "%d/", len); op = ip; nl = 0; sum = fchksum; do { if ((*ip &= 0177) >= '\172') { if (special) { DEBUG(8, "%d", nl); special = 0; op = buf; if (*ip++ != '\176' || (i = --len) > 5) goto dcorr; while (i--) *op++ = *ip++ & 0177; while (len < 5) { i = frdbuf(&buf[len], 5 - len, fn); if (i == FAIL) { len = FAIL; goto dcorr; } DEBUG(8, ",%d", i); len += i; *rlen += i; while (i--) *op++ &= 0177; } if (buf[4] != '\r') goto dcorr; sscanf(buf, "%4x", &fchksum); DEBUG(8, "\nchecksum: %04x\n", sum); if (fchksum == sum) return FIBUFSIZ + 1 + nl; else { DEBUG(8, "\n", 0); DEBUG(4, "Bad checksum\n", 0); return FAIL; } } special = *ip++; } else { if (*ip < '\040') { /* error: shouldn't get control chars */ DEBUG(4, "illegal char: %04o\n", *ip); goto dcorr; } switch (special) { case 0: c = *ip++; break; case '\172': c = *ip++ - 0100; break; case '\173': c = *ip++ + 0100; break; case '\174': c = *ip++ + 0100; break; case '\175': c = *ip++ + 0200; break; case '\176': c = *ip++ + 0300; break; } *op++ = c; if (sum & 0x8000) { sum <<= 1; sum++; } else sum <<= 1; sum += c & 0377; sum &= 0xffff; special = 0; nl++; } } while (--len); fchksum = sum; DEBUG(8, "%d ", nl); return nl;dcorr: DEBUG(8, "\n", 0); DEBUG(4, "Data corrupted\n", 0); while (len != FAIL) { if ((len = frdbuf(erbp, FIBUFSIZ, fn)) != FAIL) *rlen += len; } return FAIL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -