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