1*23599Sbloom #ifndef lint 2*23599Sbloom static char sccsid[] = "@(#)fio.c 5.1 (Berkeley) 06/19/85"; 3*23599Sbloom #endif 4*23599Sbloom 5*23599Sbloom /* 6*23599Sbloom * flow control protocol. 7*23599Sbloom * 8*23599Sbloom * This protocol relies on flow control of the data stream. 9*23599Sbloom * It is meant for working over links that can (almost) be 10*23599Sbloom * guaranteed to be errorfree, specifically X.25/PAD links. 11*23599Sbloom * A sumcheck is carried out over a whole file only. If a 12*23599Sbloom * transport fails the receiver can request retransmission(s). 13*23599Sbloom * This protocol uses a 7-bit datapath only, so it can be 14*23599Sbloom * used on links that are not 8-bit transparent. 15*23599Sbloom * 16*23599Sbloom * When using this protocol with an X.25 PAD: 17*23599Sbloom * Although this protocol uses no control chars except CR, 18*23599Sbloom * control chars NULL and ^P are used before this protocol 19*23599Sbloom * is started; since ^P is the default char for accessing 20*23599Sbloom * PAD X.28 command mode, be sure to disable that access 21*23599Sbloom * (PAD par 1). Also make sure both flow control pars 22*23599Sbloom * (5 and 12) are set. The CR used in this proto is meant 23*23599Sbloom * to trigger packet transmission, hence par 3 should be 24*23599Sbloom * set to 2; a good value for the Idle Timer (par 4) is 10. 25*23599Sbloom * All other pars should be set to 0. 26*23599Sbloom * Normally a calling site will take care of setting the 27*23599Sbloom * local PAD pars via an X.28 command and those of the remote 28*23599Sbloom * PAD via an X.29 command, unless the remote site has a 29*23599Sbloom * special channel assigned for this protocol with the proper 30*23599Sbloom * par settings. 31*23599Sbloom * 32*23599Sbloom * Author: Piet Beertema, CWI, Amsterdam, Sep 1984 33*23599Sbloom */ 34*23599Sbloom 35*23599Sbloom #include <signal.h> 36*23599Sbloom #include "uucp.h" 37*23599Sbloom #ifdef USG 38*23599Sbloom #include <termio.h> 39*23599Sbloom #else !USG 40*23599Sbloom #include <sgtty.h> 41*23599Sbloom #endif !USG 42*23599Sbloom #include <setjmp.h> 43*23599Sbloom 44*23599Sbloom #define FBUFSIZ 256 45*23599Sbloom 46*23599Sbloom #ifndef MAXMSGLEN 47*23599Sbloom #define MAXMSGLEN BUFSIZ 48*23599Sbloom #endif MAXMSGLEN 49*23599Sbloom 50*23599Sbloom static int fchksum; 51*23599Sbloom static jmp_buf Ffailbuf; 52*23599Sbloom 53*23599Sbloom static 54*23599Sbloom falarm() 55*23599Sbloom { 56*23599Sbloom signal(SIGALRM, falarm); 57*23599Sbloom longjmp(Ffailbuf, 1); 58*23599Sbloom } 59*23599Sbloom 60*23599Sbloom static int (*fsig)(); 61*23599Sbloom 62*23599Sbloom #ifndef USG 63*23599Sbloom #define TCGETA TIOCGETP 64*23599Sbloom #define TCSETA TIOCSETP 65*23599Sbloom #define termio sgttyb 66*23599Sbloom #endif USG 67*23599Sbloom 68*23599Sbloom fturnon() 69*23599Sbloom { 70*23599Sbloom int ret; 71*23599Sbloom struct termio ttbuf; 72*23599Sbloom 73*23599Sbloom ioctl(Ifn, TCGETA, &ttbuf); 74*23599Sbloom #ifdef USG 75*23599Sbloom ttbuf.c_iflag = IXOFF|IXON|ISTRIP; 76*23599Sbloom ttbuf.c_cc[VMIN] = FBUFSIZ > 64 ? 64 : FBUFSIZ; 77*23599Sbloom ttbuf.c_cc[VTIME] = 5; 78*23599Sbloom #else 79*23599Sbloom ttbuf.sg_flags = ANYP|CBREAK|TANDEM; 80*23599Sbloom #endif USG 81*23599Sbloom ret = ioctl(Ifn, TCSETA, &ttbuf); 82*23599Sbloom ASSERT(ret >= 0, "STTY FAILED", "", ret); 83*23599Sbloom fsig = signal(SIGALRM, falarm); 84*23599Sbloom /* give the other side time to perform its ioctl; 85*23599Sbloom * otherwise it may flush out the first data this 86*23599Sbloom * side is about to send. 87*23599Sbloom */ 88*23599Sbloom sleep(2); 89*23599Sbloom return SUCCESS; 90*23599Sbloom } 91*23599Sbloom 92*23599Sbloom fturnoff() 93*23599Sbloom { 94*23599Sbloom (void) signal(SIGALRM, fsig); 95*23599Sbloom return SUCCESS; 96*23599Sbloom } 97*23599Sbloom 98*23599Sbloom fwrmsg(type, str, fn) 99*23599Sbloom register char *str; 100*23599Sbloom int fn; 101*23599Sbloom char type; 102*23599Sbloom { 103*23599Sbloom register char *s; 104*23599Sbloom char bufr[MAXMSGLEN]; 105*23599Sbloom 106*23599Sbloom s = bufr; 107*23599Sbloom *s++ = type; 108*23599Sbloom while (*str) 109*23599Sbloom *s++ = *str++; 110*23599Sbloom if (*(s-1) == '\n') 111*23599Sbloom s--; 112*23599Sbloom *s++ = '\r'; 113*23599Sbloom (void) write(fn, bufr, s - bufr); 114*23599Sbloom return SUCCESS; 115*23599Sbloom } 116*23599Sbloom 117*23599Sbloom frdmsg(str, fn) 118*23599Sbloom register char *str; 119*23599Sbloom register int fn; 120*23599Sbloom { 121*23599Sbloom register char *smax; 122*23599Sbloom 123*23599Sbloom if (setjmp(Ffailbuf)) 124*23599Sbloom return FAIL; 125*23599Sbloom smax = str + MAXMSGLEN - 1; 126*23599Sbloom (void) alarm(2*MAXMSGTIME); 127*23599Sbloom for (;;) { 128*23599Sbloom if (read(fn, str, 1) <= 0) 129*23599Sbloom goto msgerr; 130*23599Sbloom if (*str == '\r') 131*23599Sbloom break; 132*23599Sbloom if (*str < ' ') 133*23599Sbloom continue; 134*23599Sbloom if (str++ >= smax) 135*23599Sbloom goto msgerr; 136*23599Sbloom } 137*23599Sbloom *str = '\0'; 138*23599Sbloom (void) alarm(0); 139*23599Sbloom return SUCCESS; 140*23599Sbloom msgerr: 141*23599Sbloom (void) alarm(0); 142*23599Sbloom return FAIL; 143*23599Sbloom } 144*23599Sbloom 145*23599Sbloom fwrdata(fp1, fn) 146*23599Sbloom FILE *fp1; 147*23599Sbloom int fn; 148*23599Sbloom { 149*23599Sbloom register int flen, alen, ret; 150*23599Sbloom char ibuf[FBUFSIZ]; 151*23599Sbloom char ack; 152*23599Sbloom long abytes, fbytes; 153*23599Sbloom struct timeb t1, t2; 154*23599Sbloom int mil, retries = 0; 155*23599Sbloom 156*23599Sbloom ret = FAIL; 157*23599Sbloom retry: 158*23599Sbloom fchksum = 0xffff; 159*23599Sbloom abytes = fbytes = 0L; 160*23599Sbloom ack = '\0'; 161*23599Sbloom #ifdef USG 162*23599Sbloom time(&t1.time); 163*23599Sbloom t1.millitm = 0; 164*23599Sbloom #else !USG 165*23599Sbloom ftime(&t1); 166*23599Sbloom #endif !USG 167*23599Sbloom while ((flen = fread(ibuf, sizeof (char), FBUFSIZ, fp1)) > 0) { 168*23599Sbloom alen = fwrblk(fn, ibuf, flen); 169*23599Sbloom abytes += alen >= 0 ? alen : -alen; 170*23599Sbloom if (alen <= 0) 171*23599Sbloom goto acct; 172*23599Sbloom fbytes += flen; 173*23599Sbloom } 174*23599Sbloom sprintf(ibuf, "\176\176%04x\r", fchksum); 175*23599Sbloom abytes += alen = strlen(ibuf); 176*23599Sbloom if (write(fn, ibuf, alen) == alen) { 177*23599Sbloom DEBUG(8, "%d\n", alen); 178*23599Sbloom DEBUG(8, "checksum: %04x\n", fchksum); 179*23599Sbloom if (frdmsg(ibuf, fn) != FAIL) { 180*23599Sbloom if ((ack = ibuf[0]) == 'G') 181*23599Sbloom ret = 0; 182*23599Sbloom DEBUG(4, "ack - '%c'\n", ack); 183*23599Sbloom } 184*23599Sbloom } 185*23599Sbloom acct: 186*23599Sbloom if (ack == 'R') { 187*23599Sbloom DEBUG(4, "RETRY:\n", 0); 188*23599Sbloom fseek(fp1, 0L, 0); 189*23599Sbloom retries++; 190*23599Sbloom goto retry; 191*23599Sbloom } 192*23599Sbloom #ifdef USG 193*23599Sbloom time(&t2.time); 194*23599Sbloom t2.millitm = 0; 195*23599Sbloom #else !USG 196*23599Sbloom ftime(&t2); 197*23599Sbloom #endif !USG 198*23599Sbloom Now = t2; 199*23599Sbloom t2.time -= t1.time; 200*23599Sbloom mil = t2.millitm - t1.millitm; 201*23599Sbloom if (mil < 0) { 202*23599Sbloom --t2.time; 203*23599Sbloom mil += 1000; 204*23599Sbloom } 205*23599Sbloom sprintf(ibuf, "sent data %ld bytes %ld.%02d secs", 206*23599Sbloom fbytes, (long)t2.time, mil/10); 207*23599Sbloom sysacct(abytes, t2.time - t1.time); 208*23599Sbloom if (retries > 0) 209*23599Sbloom sprintf((char *)ibuf+strlen(ibuf)," %d retries", retries); 210*23599Sbloom DEBUG(1, "%s\n", ibuf); 211*23599Sbloom syslog(ibuf); 212*23599Sbloom #ifdef SYSACCT 213*23599Sbloom if (ret) 214*23599Sbloom sysaccf(NULL); /* force accounting */ 215*23599Sbloom #endif SYSACCT 216*23599Sbloom return ret; 217*23599Sbloom } 218*23599Sbloom 219*23599Sbloom /* max. attempts to retransmit a file: */ 220*23599Sbloom #define MAXRETRIES (fbytes < 10000L ? 2 : 1) 221*23599Sbloom 222*23599Sbloom frddata(fn, fp2) 223*23599Sbloom register int fn; 224*23599Sbloom register FILE *fp2; 225*23599Sbloom { 226*23599Sbloom register int flen; 227*23599Sbloom register char eof; 228*23599Sbloom char ibuf[FBUFSIZ]; 229*23599Sbloom int ret, retries = 0; 230*23599Sbloom long alen, abytes, fbytes; 231*23599Sbloom struct timeb t1, t2; 232*23599Sbloom int mil; 233*23599Sbloom 234*23599Sbloom ret = FAIL; 235*23599Sbloom retry: 236*23599Sbloom fchksum = 0xffff; 237*23599Sbloom abytes = fbytes = 0L; 238*23599Sbloom #ifdef USG 239*23599Sbloom time(&t1.time); 240*23599Sbloom t1.millitm = 0; 241*23599Sbloom #else !USG 242*23599Sbloom ftime(&t1); 243*23599Sbloom #endif !USG 244*23599Sbloom do { 245*23599Sbloom flen = frdblk(ibuf, fn, &alen); 246*23599Sbloom abytes += alen; 247*23599Sbloom if (flen < 0) 248*23599Sbloom goto acct; 249*23599Sbloom if (eof = flen > FBUFSIZ) 250*23599Sbloom flen -= FBUFSIZ + 1; 251*23599Sbloom fbytes += flen; 252*23599Sbloom if (fwrite(ibuf, sizeof (char), flen, fp2) != flen) 253*23599Sbloom goto acct; 254*23599Sbloom } while (!eof); 255*23599Sbloom ret = 0; 256*23599Sbloom acct: 257*23599Sbloom if (ret) { 258*23599Sbloom if (retries++ < MAXRETRIES) { 259*23599Sbloom DEBUG(8, "send ack: 'R'\n", 0); 260*23599Sbloom fwrmsg('R', "", fn); 261*23599Sbloom fseek(fp2, 0L, 0); 262*23599Sbloom DEBUG(4, "RETRY:\n", 0); 263*23599Sbloom goto retry; 264*23599Sbloom } 265*23599Sbloom DEBUG(8, "send ack: 'Q'\n", 0); 266*23599Sbloom fwrmsg('Q', "", fn); 267*23599Sbloom #ifdef SYSACCT 268*23599Sbloom sysaccf(NULL); /* force accounting */ 269*23599Sbloom #endif SYSACCT 270*23599Sbloom } else { 271*23599Sbloom DEBUG(8, "send ack: 'G'\n", 0); 272*23599Sbloom fwrmsg('G', "", fn); 273*23599Sbloom } 274*23599Sbloom #ifdef USG 275*23599Sbloom time(&t2.time); 276*23599Sbloom t2.millitm = 0; 277*23599Sbloom #else !USG 278*23599Sbloom ftime(&t2); 279*23599Sbloom #endif !USG 280*23599Sbloom Now = t2; 281*23599Sbloom t2.time -= t1.time; 282*23599Sbloom mil = t2.millitm - t1.millitm; 283*23599Sbloom if (mil < 0) { 284*23599Sbloom --t2.time; 285*23599Sbloom mil += 1000; 286*23599Sbloom } 287*23599Sbloom sprintf(ibuf, "received data %ld bytes %ld.%02d secs", 288*23599Sbloom fbytes, (long)t2.time, mil/10); 289*23599Sbloom sysacct(abytes, t2.time - t1.time); 290*23599Sbloom if (retries > 0) 291*23599Sbloom sprintf((char *)ibuf+strlen(ibuf)," %d retries", retries); 292*23599Sbloom DEBUG(1, "%s\n", ibuf); 293*23599Sbloom syslog(ibuf); 294*23599Sbloom return ret; 295*23599Sbloom } 296*23599Sbloom 297*23599Sbloom static 298*23599Sbloom frdbuf(blk, len, fn) 299*23599Sbloom register char *blk; 300*23599Sbloom register int len; 301*23599Sbloom register int fn; 302*23599Sbloom { 303*23599Sbloom static int ret = FBUFSIZ / 2; 304*23599Sbloom #ifndef Not080 305*23599Sbloom extern int linebaudrate; 306*23599Sbloom #endif Not080 307*23599Sbloom 308*23599Sbloom if (setjmp(Ffailbuf)) 309*23599Sbloom return FAIL; 310*23599Sbloom #ifndef Not080 311*23599Sbloom if (len == FBUFSIZ && ret < FBUFSIZ / 2 && 312*23599Sbloom linebaudrate > 0 && linebaudrate < 4800) 313*23599Sbloom sleep(1); 314*23599Sbloom #endif Not080 315*23599Sbloom (void) alarm(MAXMSGTIME); 316*23599Sbloom ret = read(fn, blk, len); 317*23599Sbloom alarm(0); 318*23599Sbloom return ret <= 0 ? FAIL : ret; 319*23599Sbloom } 320*23599Sbloom 321*23599Sbloom /* call ultouch every TC calls to either frdblk or fwrblk */ 322*23599Sbloom 323*23599Sbloom #define TC 20 324*23599Sbloom static int tc = TC; 325*23599Sbloom 326*23599Sbloom /* Byte conversion: 327*23599Sbloom * 328*23599Sbloom * from pre to 329*23599Sbloom * 000-037 172 100-137 330*23599Sbloom * 040-171 040-171 331*23599Sbloom * 172-177 173 072-077 332*23599Sbloom * 200-237 174 100-137 333*23599Sbloom * 240-371 175 040-171 334*23599Sbloom * 372-377 176 072-077 335*23599Sbloom */ 336*23599Sbloom 337*23599Sbloom static 338*23599Sbloom fwrblk(fn, ip, len) 339*23599Sbloom int fn; 340*23599Sbloom register char *ip; 341*23599Sbloom register int len; 342*23599Sbloom { 343*23599Sbloom register char *op; 344*23599Sbloom register int sum, nl; 345*23599Sbloom int ret; 346*23599Sbloom char obuf[FBUFSIZ * 2]; 347*23599Sbloom 348*23599Sbloom /* call ultouch occasionally */ 349*23599Sbloom if (--tc < 0) { 350*23599Sbloom tc = TC; 351*23599Sbloom ultouch(); 352*23599Sbloom } 353*23599Sbloom DEBUG(8, "%d/", len); 354*23599Sbloom op = obuf; 355*23599Sbloom nl = 0; 356*23599Sbloom sum = fchksum; 357*23599Sbloom do { 358*23599Sbloom if (sum & 0x8000) { 359*23599Sbloom sum <<= 1; 360*23599Sbloom sum++; 361*23599Sbloom } else 362*23599Sbloom sum <<= 1; 363*23599Sbloom sum += *ip & 0377; 364*23599Sbloom sum &= 0xffff; 365*23599Sbloom if (*ip & 0200) { 366*23599Sbloom *ip &= 0177; 367*23599Sbloom if (*ip < 040) { 368*23599Sbloom *op++ = '\174'; 369*23599Sbloom *op++ = *ip++ + 0100; 370*23599Sbloom } else 371*23599Sbloom if (*ip <= 0171) { 372*23599Sbloom *op++ = '\175'; 373*23599Sbloom *op++ = *ip++; 374*23599Sbloom } 375*23599Sbloom else { 376*23599Sbloom *op++ = '\176'; 377*23599Sbloom *op++ = *ip++ - 0100; 378*23599Sbloom } 379*23599Sbloom nl += 2; 380*23599Sbloom } else { 381*23599Sbloom if (*ip < 040) { 382*23599Sbloom *op++ = '\172'; 383*23599Sbloom *op++ = *ip++ + 0100; 384*23599Sbloom nl += 2; 385*23599Sbloom } else 386*23599Sbloom if (*ip <= 0171) { 387*23599Sbloom *op++ = *ip++; 388*23599Sbloom nl++; 389*23599Sbloom } else { 390*23599Sbloom *op++ = '\173'; 391*23599Sbloom *op++ = *ip++ - 0100; 392*23599Sbloom nl += 2; 393*23599Sbloom } 394*23599Sbloom } 395*23599Sbloom } while (--len); 396*23599Sbloom fchksum = sum; 397*23599Sbloom DEBUG(8, "%d,", nl); 398*23599Sbloom ret = write(fn, obuf, nl); 399*23599Sbloom return ret == nl ? nl : ret < 0 ? 0 : -ret; 400*23599Sbloom } 401*23599Sbloom 402*23599Sbloom static 403*23599Sbloom frdblk(ip, fn, rlen) 404*23599Sbloom register char *ip; 405*23599Sbloom int fn; 406*23599Sbloom long *rlen; 407*23599Sbloom { 408*23599Sbloom register char *op, c; 409*23599Sbloom register int sum, len, nl; 410*23599Sbloom char buf[5], *erbp = ip; 411*23599Sbloom int i; 412*23599Sbloom static char special = 0; 413*23599Sbloom 414*23599Sbloom /* call ultouch occasionally */ 415*23599Sbloom if (--tc < 0) { 416*23599Sbloom tc = TC; 417*23599Sbloom ultouch(); 418*23599Sbloom } 419*23599Sbloom 420*23599Sbloom if ((len = frdbuf(ip, FBUFSIZ, fn)) == FAIL) { 421*23599Sbloom *rlen = 0; 422*23599Sbloom goto dcorr; 423*23599Sbloom } 424*23599Sbloom *rlen = len; 425*23599Sbloom DEBUG(8, "%d/", len); 426*23599Sbloom op = ip; 427*23599Sbloom nl = 0; 428*23599Sbloom sum = fchksum; 429*23599Sbloom do { 430*23599Sbloom if ((*ip &= 0177) >= '\172') { 431*23599Sbloom if (special) { 432*23599Sbloom DEBUG(8, "%d", nl); 433*23599Sbloom special = 0; 434*23599Sbloom op = buf; 435*23599Sbloom if (*ip++ != '\176' || (i = --len) > 5) 436*23599Sbloom goto dcorr; 437*23599Sbloom while (i--) 438*23599Sbloom *op++ = *ip++; 439*23599Sbloom while (len < 5) { 440*23599Sbloom i = frdbuf(&buf[len], 5 - len, fn); 441*23599Sbloom if (i == FAIL) { 442*23599Sbloom len = FAIL; 443*23599Sbloom goto dcorr; 444*23599Sbloom } 445*23599Sbloom DEBUG(8, ",%d", i); 446*23599Sbloom len += i; 447*23599Sbloom *rlen += i; 448*23599Sbloom } 449*23599Sbloom if (buf[4] != '\r') 450*23599Sbloom goto dcorr; 451*23599Sbloom sscanf(buf, "%4x", &fchksum); 452*23599Sbloom DEBUG(8, "\nchecksum: %04x\n", sum); 453*23599Sbloom if (fchksum == sum) 454*23599Sbloom return FBUFSIZ + 1 + nl; 455*23599Sbloom else { 456*23599Sbloom DEBUG(8, "\n", 0); 457*23599Sbloom DEBUG(4, "Bad checksum\n", 0); 458*23599Sbloom return FAIL; 459*23599Sbloom } 460*23599Sbloom } 461*23599Sbloom special = *ip++; 462*23599Sbloom } else { 463*23599Sbloom if (*ip < '\040') { 464*23599Sbloom /* error: shouldn't get control chars */ 465*23599Sbloom goto dcorr; 466*23599Sbloom } 467*23599Sbloom switch (special) { 468*23599Sbloom case 0: 469*23599Sbloom c = *ip++; 470*23599Sbloom break; 471*23599Sbloom case '\172': 472*23599Sbloom c = *ip++ - 0100; 473*23599Sbloom break; 474*23599Sbloom case '\173': 475*23599Sbloom c = *ip++ + 0100; 476*23599Sbloom break; 477*23599Sbloom case '\174': 478*23599Sbloom c = *ip++ + 0100; 479*23599Sbloom break; 480*23599Sbloom case '\175': 481*23599Sbloom c = *ip++ + 0200; 482*23599Sbloom break; 483*23599Sbloom case '\176': 484*23599Sbloom c = *ip++ + 0300; 485*23599Sbloom break; 486*23599Sbloom } 487*23599Sbloom *op++ = c; 488*23599Sbloom if (sum & 0x8000) { 489*23599Sbloom sum <<= 1; 490*23599Sbloom sum++; 491*23599Sbloom } else 492*23599Sbloom sum <<= 1; 493*23599Sbloom sum += c & 0377; 494*23599Sbloom sum &= 0xffff; 495*23599Sbloom special = 0; 496*23599Sbloom nl++; 497*23599Sbloom } 498*23599Sbloom } while (--len); 499*23599Sbloom fchksum = sum; 500*23599Sbloom DEBUG(8, "%d,", nl); 501*23599Sbloom return nl; 502*23599Sbloom dcorr: 503*23599Sbloom DEBUG(8, "\n", 0); 504*23599Sbloom DEBUG(4, "Data corrupted\n", 0); 505*23599Sbloom while (len != FAIL) { 506*23599Sbloom if ((len = frdbuf(erbp, FBUFSIZ, fn)) != FAIL) 507*23599Sbloom *rlen += len; 508*23599Sbloom } 509*23599Sbloom return FAIL; 510*23599Sbloom } 511