new version of uucp f-proto
Piet Beertema
piet at mcvax.UUCP
Tue Oct 8 20:48:39 AEST 1985
<>
Here's a new version of the f-proto for uucp. Compared to the one I posted
quite some time ago the major differences are:
- it has been adapted to run cost-effective on X.25 hosts; the old version
produced too many short packets on such hosts;
- a few minor bugs have been fixed (hence the posting to net.bugs.uucp too).
If you're already running 4.3bsd uucp, you can replace the fio.c by this one
without modifications.
-----------------------------------------------------------
#This is a shell archive; extract with /bin/sh
echo -n 'Extracting n.fio.c... '
sed 's/^M//' >n.fio.c <<\SHAREND
M/* fio.c 3.3 85/10/08 (CWI) */
M
M/*
M * flow control protocol.
M *
M * This protocol relies on flow control of the data stream.
M * It is meant for working over links that can (almost) be
M * guaranteed to be errorfree, specifically X.25/PAD links.
M * A sumcheck is carried out over a whole file only. If a
M * transport fails the receiver can request retransmission(s).
M * This protocol uses a 7-bit datapath only, so it can be
M * used on links that are not 8-bit transparent.
M *
M * When using this protocol with an X.25 PAD:
M * Although this protocol uses no control chars except CR,
M * control chars NULL and ^P are used before this protocol
M * is started; since ^P is the default char for accessing
M * PAD X.28 command mode, be sure to disable that access
M * (PAD par 1). Also make sure both flow control pars
M * (5 and 12) are set. The CR used in this proto is meant
M * to trigger packet transmission, hence par 3 should be
M * set to 2; a good value for the Idle Timer (par 4) is 10.
M * All other pars should be set to 0.
M *
M * Normally a calling site will take care of setting the
M * local PAD pars via an X.28 command and those of the remote
M * PAD via an X.29 command, unless the remote site has a
M * special channel assigned for this protocol with the proper
M * par settings.
M *
M * Additional comments for hosts with direct X.25 access:
M * - the global variable IsTcpIp, when set, excludes ioctl's,
M * so the same binary can run on X.25 and non-X.25 hosts;
M * - reads are done in small chunks, which can be smaller than
M * the packet size; your X.25 driver must support that.
M *
M *
M * Author:
M * Piet Beertema, CWI, Amsterdam, Sep 1984
M * Modified for X.25 hosts:
M * Robert Elz, Melbourne Univ, Mar 1985
M */
M
M#include "uucp.h"
M#include <signal.h>
M#ifdef USG
M#include <termio.h>
M#else !USG
M#include <sgtty.h>
M#endif !USG
M#include <setjmp.h>
M
M#define FIBUFSIZ 256 /* for X.25 interfaces: set equal to packet size,
M * but see comment above
M */
M
M#define FOBUFSIZ 1024 /* for X.25 interfaces: set equal to packet size;
M * otherwise make as large as feasible to reduce
M * number of write system calls
M */
M
M#ifndef MAXMSGLEN
M#define MAXMSGLEN BUFSIZ
M#endif MAXMSGLEN
M
Mstatic int fchksum;
Mstatic jmp_buf Ffailbuf;
M
Mstatic
Mfalarm()
M{
M signal(SIGALRM, falarm);
M longjmp(Ffailbuf, 1);
M}
M
Mstatic int (*fsig)();
M
M#ifndef USG
M#define TCGETA TIOCGETP
M#define TCSETA TIOCSETP
M#define termio sgttyb
M#endif USG
M
Mfturnon()
M{
M int ret;
M struct termio ttbuf;
M
M if (!IsTcpIp) {
M ioctl(Ifn, TCGETA, &ttbuf);
M#ifdef USG
M ttbuf.c_iflag = IXOFF|IXON|ISTRIP;
M ttbuf.c_cc[VMIN] = FIBUFSIZ > 64 ? 64 : FIBUFSIZ;
M ttbuf.c_cc[VTIME] = 5;
M#else !USG
M ttbuf.sg_flags = ANYP|CBREAK|TANDEM;
M#endif USG
M ret = ioctl(Ifn, TCSETA, &ttbuf);
M ASSERT(ret >= 0, "STTY FAILED", "", ret);
M }
M fsig = signal(SIGALRM, falarm);
M /* give the other side time to perform its ioctl;
M * otherwise it may flush out the first data this
M * side is about to send.
M */
M sleep(2);
M return SUCCESS;
M}
M
Mfturnoff()
M{
M (void) signal(SIGALRM, fsig);
M return SUCCESS;
M}
M
Mfwrmsg(type, str, fn)
Mregister char *str;
Mint fn;
Mchar type;
M{
M register char *s;
M char bufr[MAXMSGLEN];
M
M s = bufr;
M *s++ = type;
M while (*str)
M *s++ = *str++;
M if (*(s-1) == '\n')
M s--;
M *s++ = '\r';
M *s = 0;
M (void) write(fn, bufr, s - bufr);
M return SUCCESS;
M}
M
Mfrdmsg(str, fn)
Mregister char *str;
Mregister int fn;
M{
M register char *smax;
M
M if (setjmp(Ffailbuf))
M return FAIL;
M smax = str + MAXMSGLEN - 1;
M (void) alarm(2*MAXMSGTIME);
M for (;;) {
M if (read(fn, str, 1) <= 0)
M goto msgerr;
M *str &= 0177;
M if (*str == '\r')
M break;
M if (*str < ' ') {
M continue;
M }
M if (str++ >= smax)
M goto msgerr;
M }
M *str = '\0';
M (void) alarm(0);
M return SUCCESS;
Mmsgerr:
M (void) alarm(0);
M return FAIL;
M}
M
Mfwrdata(fp1, fn)
MFILE *fp1;
Mint fn;
M{
M register int alen, ret;
M register char *obp;
M char ack, ibuf[MAXMSGLEN];
M int flen, mil, retries = 0;
M long abytes, fbytes;
M struct timeb t1, t2;
M
M ret = FAIL;
Mretry:
M fchksum = 0xffff;
M abytes = fbytes = 0L;
M ack = '\0';
M#ifdef USG
M time(&t1.time);
M t1.millitm = 0;
M#else !USG
M ftime(&t1);
M#endif !USG
M do {
M alen = fwrblk(fn, fp1, &flen);
M fbytes += flen;
M if (alen <= 0) {
M abytes -= alen;
M goto acct;
M }
M abytes += alen;
M } while (!feof(fp1) && !ferror(fp1));
M DEBUG(8, "\nchecksum: %04x\n", fchksum);
M if (frdmsg(ibuf, fn) != FAIL) {
M if ((ack = ibuf[0]) == 'G')
M ret = SUCCESS;
M DEBUG(4, "ack - '%c'\n", ack);
M }
Macct:
M#ifdef USG
M time(&t2.time);
M t2.millitm = 0;
M#else !USG
M ftime(&t2);
M#endif !USG
M Now = t2;
M t2.time -= t1.time;
M mil = t2.millitm - t1.millitm;
M if (mil < 0) {
M --t2.time;
M mil += 1000;
M }
M sprintf(ibuf, "sent data %ld bytes %ld.%02d secs",
M fbytes, (long)t2.time, mil / 10);
M sysacct(abytes, t2.time - t1.time);
M if (retries > 0)
M sprintf(&ibuf[strlen(ibuf)], ", retry #%d", retries);
M DEBUG(1, "%s\n", ibuf);
M syslog(ibuf);
M if (ack == 'R') {
M DEBUG(4, "RETRY:\n", 0);
M fseek(fp1, 0L, 0);
M retries++;
M goto retry;
M }
M#ifdef SYSACCT
M if (ret == FAIL)
M sysaccf(NULL); /* force accounting */
M#endif SYSACCT
M return ret;
M}
M
M/* max. attempts to retransmit a file: */
M#define MAXRETRIES (fbytes < 10000L ? 2 : 1)
M
Mfrddata(fn, fp2)
Mregister int fn;
Mregister FILE *fp2;
M{
M register int flen;
M register char eof;
M char ibuf[FIBUFSIZ];
M int ret, mil, retries = 0;
M long alen, abytes, fbytes;
M struct timeb t1, t2;
M
M ret = FAIL;
Mretry:
M fchksum = 0xffff;
M abytes = fbytes = 0L;
M#ifdef USG
M time(&t1.time);
M t1.millitm = 0;
M#else !USG
M ftime(&t1);
M#endif !USG
M do {
M flen = frdblk(ibuf, fn, &alen);
M abytes += alen;
M if (flen < 0)
M goto acct;
M if (eof = flen > FIBUFSIZ)
M flen -= FIBUFSIZ + 1;
M fbytes += flen;
M if (fwrite(ibuf, sizeof (char), flen, fp2) != flen)
M goto acct;
M } while (!eof);
M ret = SUCCESS;
Macct:
M#ifdef USG
M time(&t2.time);
M t2.millitm = 0;
M#else !USG
M ftime(&t2);
M#endif !USG
M Now = t2;
M t2.time -= t1.time;
M mil = t2.millitm - t1.millitm;
M if (mil < 0) {
M --t2.time;
M mil += 1000;
M }
M sprintf(ibuf, "received data %ld bytes %ld.%02d secs",
M fbytes, (long)t2.time, mil/10);
M sysacct(abytes, t2.time - t1.time);
M DEBUG(1, "%s\n", ibuf);
M syslog(ibuf);
M if (ret == FAIL) {
M if (retries++ < MAXRETRIES) {
M DEBUG(8, "send ack: 'R'\n", 0);
M fwrmsg('R', "", fn);
M fseek(fp2, 0L, 0);
M DEBUG(4, "RETRY:\n", 0);
M goto retry;
M }
M DEBUG(8, "send ack: 'Q'\n", 0);
M fwrmsg('Q', "", fn);
M#ifdef SYSACCT
M sysaccf(NULL); /* force accounting */
M#endif SYSACCT
M }
M else {
M DEBUG(8, "send ack: 'G'\n", 0);
M fwrmsg('G', "", fn);
M }
M return ret;
M}
M
Mstatic
Mfrdbuf(blk, len, fn)
Mregister char *blk;
Mregister int len;
Mregister int fn;
M{
M static int ret = FIBUFSIZ / 2;
M
M if (setjmp(Ffailbuf))
M return FAIL;
M (void) alarm(MAXMSGTIME);
M ret = read(fn, blk, len);
M alarm(0);
M return ret <= 0 ? FAIL : ret;
M}
M
M/* call ultouch every TC calls to either frdblk or fwrblk */
M#define TC 20
Mstatic int tc = TC;
M
M/* Byte conversion:
M *
M * from pre to
M * 000-037 172 100-137
M * 040-171 040-171
M * 172-177 173 072-077
M * 200-237 174 100-137
M * 240-371 175 040-171
M * 372-377 176 072-077
M */
M
Mstatic
Mfwrblk(fn, fp, lenp)
Mint fn;
Mregister FILE *fp;
Mint *lenp;
M{
M register char *op;
M register int c, sum, nl, len;
M char obuf[FOBUFSIZ + 8];
M int ret;
M
M /* call ultouch occasionally */
M if (--tc < 0) {
M tc = TC;
M ultouch();
M }
M op = obuf;
M nl = 0;
M len = 0;
M sum = fchksum;
M while ((c = getc(fp)) != EOF) {
M len++;
M if (sum & 0x8000) {
M sum <<= 1;
M sum++;
M } else
M sum <<= 1;
M sum += c;
M sum &= 0xffff;
M if (c & 0200) {
M c &= 0177;
M if (c < 040) {
M *op++ = '\174';
M *op++ = c + 0100;
M } else
M if (c <= 0171) {
M *op++ = '\175';
M *op++ = c;
M }
M else {
M *op++ = '\176';
M *op++ = c - 0100;
M }
M nl += 2;
M } else {
M if (c < 040) {
M *op++ = '\172';
M *op++ = c + 0100;
M nl += 2;
M } else
M if (c <= 0171) {
M *op++ = c;
M nl++;
M } else {
M *op++ = '\173';
M *op++ = c - 0100;
M nl += 2;
M }
M }
M if (nl >= FOBUFSIZ - 1) {
M /*
M * peek at next char, see if it will fit
M */
M c = getc(fp);
M if (c == EOF)
M break;
M (void) ungetc(c, fp);
M if (nl >= FOBUFSIZ || c < 040 || c > 0171)
M goto writeit;
M }
M }
M /*
M * At EOF - append checksum, there is space for it...
M */
M sprintf(op, "\176\176%04x\r", sum);
M nl += strlen(op);
Mwriteit:
M *lenp = len;
M fchksum = sum;
M DEBUG(8, "%d/", len);
M DEBUG(8, "%d ", nl);
M ret = write(fn, obuf, nl);
M return ret == nl ? nl : ret < 0 ? 0 : -ret;
M}
M
Mstatic
Mfrdblk(ip, fn, rlen)
Mregister char *ip;
Mint fn;
Mlong *rlen;
M{
M register char *op, c;
M register int sum, len, nl;
M char buf[5], *erbp = ip;
M int i;
M static char special = 0;
M
M /* call ultouch occasionally */
M if (--tc < 0) {
M tc = TC;
M ultouch();
M }
M if ((len = frdbuf(ip, FIBUFSIZ, fn)) == FAIL) {
M *rlen = 0;
M goto dcorr;
M }
M *rlen = len;
M DEBUG(8, "%d/", len);
M op = ip;
M nl = 0;
M sum = fchksum;
M do {
M if ((*ip &= 0177) >= '\172') {
M if (special) {
M DEBUG(8, "%d", nl);
M special = 0;
M op = buf;
M if (*ip++ != '\176' || (i = --len) > 5)
M goto dcorr;
M while (i--)
M *op++ = *ip++ & 0177;
M while (len < 5) {
M i = frdbuf(&buf[len], 5 - len, fn);
M if (i == FAIL) {
M len = FAIL;
M goto dcorr;
M }
M DEBUG(8, ",%d", i);
M len += i;
M *rlen += i;
M while (i--)
M *op++ &= 0177;
M }
M if (buf[4] != '\r')
M goto dcorr;
M sscanf(buf, "%4x", &fchksum);
M DEBUG(8, "\nchecksum: %04x\n", sum);
M if (fchksum == sum)
M return FIBUFSIZ + 1 + nl;
M else {
M DEBUG(8, "\n", 0);
M DEBUG(4, "Bad checksum\n", 0);
M return FAIL;
M }
M }
M special = *ip++;
M } else {
M if (*ip < '\040') {
M /* error: shouldn't get control chars */
M goto dcorr;
M }
M switch (special) {
M case 0:
M c = *ip++;
M break;
M case '\172':
M c = *ip++ - 0100;
M break;
M case '\173':
M c = *ip++ + 0100;
M break;
M case '\174':
M c = *ip++ + 0100;
M break;
M case '\175':
M c = *ip++ + 0200;
M break;
M case '\176':
M c = *ip++ + 0300;
M break;
M }
M *op++ = c;
M if (sum & 0x8000) {
M sum <<= 1;
M sum++;
M } else
M sum <<= 1;
M sum += c & 0377;
M sum &= 0xffff;
M special = 0;
M nl++;
M }
M } while (--len);
M fchksum = sum;
M DEBUG(8, "%d ", nl);
M return nl;
Mdcorr:
M DEBUG(8, "\n", 0);
M DEBUG(4, "Data corrupted\n", 0);
M while (len != FAIL) {
M if ((len = frdbuf(erbp, FIBUFSIZ, fn)) != FAIL)
M *rlen += len;
M }
M return FAIL;
M}
SHAREND
echo done
exit
--
Piet Beertema, CWI, Amsterdam
(piet at mcvax.UUCP)
More information about the Comp.sources.unix
mailing list