uucp f-protocol
Piet Beertema
piet at mcvax.UUCP
Tue Jan 8 02:01:53 AEST 1985
<...>
Some bugs have been fixed in the f-protocol posted to net.sources
in December.
Also a cpu-speedup has been added to diminish the load on the cpu
at low baudrates; see "#ifdef cpuspeedup". This depends on "linebaudrate"
being set in conn.c (condevs.c).
To make things easy, here's the whole source:
---------------------------------------------------------------------
/* %M% %I% %E% (Mathematisch Centrum) */
/*
* 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 (via the L.sys file)
* 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; the remote PAD
* may even automatically issue an X.29 command to set the
* (local) PAD pars appropriately, thus avoiding the need
* to set those via the L.sys file.
*
* Author: Piet Beertema, CWI, Amsterdam, Sep 1984
*/
#include "uucp.h"
#include <signal.h>
#ifdef SIII
#include <termio.h>
#else
#include <sgtty.h>
#endif SIII
#include <setjmp.h>
#define FBUFSIZ 256
static int chksum;
static jmp_buf Ffailbuf;
static
falarm()
{
signal(SIGALRM, falarm);
longjmp(Ffailbuf, 1);
}
static int (*fsig)();
#ifndef SIII
#define TCGETA TIOCGETP
#define TCSETA TIOCSETP
#define termio sgttyb
#endif SIII
fturnon()
{
int ret;
struct termio ttbuf;
ioctl(Ifn, TCGETA, &ttbuf);
#ifdef SIII
ttbuf.c_iflag = IXOFF|IXON|ISTRIP;
ttbuf.c_cc[VMIN] = FBUFSIZ > 64 ? 64 : FBUFSIZ;
ttbuf.c_cc[VTIME] = 5;
#else
ttbuf.sg_flags = ANYP|CBREAK|TANDEM;
#endif SIII
ret = ioctl(Ifn, TCSETA, &ttbuf);
ASSERT(ret >= 0, "STTY FAILED", "", ret);
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 0;
}
fturnoff()
{
(void) signal(SIGALRM, fsig);
return 0;
}
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';
(void) write(fn, bufr, s - bufr);
return 0;
}
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;
if (*str == '\r')
break;
if (*str < ' ')
continue;
if (str++ >= smax)
goto msgerr;
}
*str = '\0';
(void) alarm(0);
return 0;
msgerr:
(void) alarm(0);
return FAIL;
}
fwrdata(fp1, fn)
FILE *fp1;
int fn;
{
register int flen, alen, ret;
register char *obp;
char ibuf[FBUFSIZ];
char ack;
long abytes, fbytes;
time_t t1, t2;
ret = FAIL;
retry:
chksum = 0xffff;
abytes = fbytes = 0L;
ack = '\0';
time(&t1);
while ((flen = fread(ibuf, sizeof (char), FBUFSIZ, fp1)) > 0) {
alen = fwrblk(fn, ibuf, flen);
abytes += alen >= 0 ? alen : -alen;
if (alen <= 0)
goto acct;
fbytes += flen;
}
sprintf(ibuf, "\176\176%04x\r", chksum);
abytes += alen = strlen(ibuf);
if (write(fn, ibuf, alen) == alen) {
DEBUG(8, "%d\n", alen);
DEBUG(8, "checksum: %04x\n", chksum);
if (frdmsg(ibuf, fn) != FAIL) {
if ((ack = ibuf[0]) == 'G')
ret = 0;
DEBUG(4, "ack - '%c'\n", ack);
}
}
acct:
time(&t2);
sprintf(ibuf, ret == 0 ?
"sent data %ld bytes %ld secs" :
"send failed after %ld bytes %ld secs",
fbytes, t2 - t1);
DEBUG(1, "%s\n", ibuf);
syslog(ibuf);
#ifdef SYSACCT
sysacct(abytes, t2 - t1);
#endif SYSACCT
if (ack == 'R') {
DEBUG(4, "RETRY:\n", 0);
fseek(fp1, 0L, 0);
goto retry;
}
#ifdef SYSACCT
if (ret)
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[FBUFSIZ];
int ret, retries = 0;
long alen, abytes, fbytes;
time_t t1, t2;
ret = FAIL;
retry:
chksum = 0xffff;
abytes = fbytes = 0L;
time(&t1);
do {
flen = frdblk(ibuf, fn, &alen);
abytes += alen;
if (flen < 0)
goto acct;
if (eof = flen > FBUFSIZ)
flen -= FBUFSIZ + 1;
fbytes += flen;
if (fwrite(ibuf, sizeof (char), flen, fp2) != flen)
goto acct;
} while (!eof);
ret = 0;
acct:
time(&t2);
sprintf(ibuf, ret == 0 ?
"received data %ld bytes %ld secs" :
"receive failed after %ld bytes %ld secs",
fbytes, t2 - t1);
DEBUG(1, "%s\n", ibuf);
syslog(ibuf);
#ifdef SYSACCT
sysacct(abytes, t2 - t1);
#endif SYSACCT
if (ret) {
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;
}
static
frdbuf(blk, len, fn)
register char *blk;
register int len;
register int fn;
{
static int ret = FBUFSIZ / 2;
#ifdef cpuspeedup
extern int linebaudrate;
#endif cpuspeedup
if (setjmp(Ffailbuf))
return FAIL;
#ifdef cpuspeedup
if (len == FBUFSIZ && ret < FBUFSIZ / 2 &&
linebaudrate > 0 && linebaudrate < 4800)
sleep(1);
#endif cpuspeedup
(void) alarm(MAXCHARTIME);
ret = read(fn, blk, len);
alarm(0);
return ret <= 0 ? FAIL : ret;
}
/* 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
*/
static
fwrblk(fn, ip, len)
int fn;
register char *ip;
register int len;
{
register char *op;
register int sum, nl;
int ret;
char obuf[FBUFSIZ * 2];
DEBUG(8, "%d/", len);
op = obuf;
nl = 0;
sum = chksum;
do {
if (sum & 0x8000) {
sum <<= 1;
sum++;
} else
sum <<= 1;
sum += *ip & 0377;
sum &= 0xffff;
if (*ip & 0200) {
*ip &= 0177;
if (*ip < 040) {
*op++ = '\174';
*op++ = *ip++ + 0100;
} else
if (*ip <= 0171) {
*op++ = '\175';
*op++ = *ip++;
}
else {
*op++ = '\176';
*op++ = *ip++ - 0100;
}
nl += 2;
} else {
if (*ip < 040) {
*op++ = '\172';
*op++ = *ip++ + 0100;
nl += 2;
} else
if (*ip <= 0171) {
*op++ = *ip++;
nl++;
} else {
*op++ = '\173';
*op++ = *ip++ - 0100;
nl += 2;
}
}
} while (--len);
chksum = sum;
DEBUG(8, "%d,", nl);
ret = write(fn, obuf, nl);
return ret == nl ? nl : ret < 0 ? 0 : -ret;
}
static
frdblk(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;
if ((len = frdbuf(ip, FBUFSIZ, fn)) == FAIL) {
*rlen = 0;
goto dcorr;
}
*rlen = len;
DEBUG(8, "%d/", len);
op = ip;
nl = 0;
sum = chksum;
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++;
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;
}
if (buf[4] != '\r')
goto dcorr;
sscanf(buf, "%4x", &chksum);
DEBUG(8, "\nchecksum: %04x\n", sum);
if (chksum == sum)
return FBUFSIZ + 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 */
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);
chksum = 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, FBUFSIZ, fn)) != FAIL)
*rlen += len;
}
return FAIL;
}
---------------------------------------------------------------------
--
Piet Beertema, CWI, Amsterdam
...{decvax,philabs}!mcvax!piet
More information about the Comp.sources.unix
mailing list