|
|
1.1 ! root 1: #ifndef lint ! 2: static char sccsid[] = "@(#)fio.c 5.3 (Berkeley) 10/9/85"; ! 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 256 /* for X.25 interfaces: set equal to packet size, ! 56: * but see comment above ! 57: */ ! 58: ! 59: #define FOBUFSIZ 256 /* 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: static ! 72: falarm() ! 73: { ! 74: signal(SIGALRM, falarm); ! 75: longjmp(Ffailbuf, 1); ! 76: } ! 77: ! 78: static int (*fsig)(); ! 79: ! 80: #ifndef USG ! 81: #define TCGETA TIOCGETP ! 82: #define TCSETA TIOCSETP ! 83: #define termio sgttyb ! 84: #endif USG ! 85: ! 86: fturnon() ! 87: { ! 88: int ret; ! 89: struct termio ttbuf; ! 90: ! 91: if (!IsTcpIp) { ! 92: ioctl(Ifn, TCGETA, &ttbuf); ! 93: #ifdef USG ! 94: ttbuf.c_iflag = IXOFF|IXON|ISTRIP; ! 95: ttbuf.c_cc[VMIN] = FIBUFSIZ > 64 ? 64 : FIBUFSIZ; ! 96: ttbuf.c_cc[VTIME] = 5; ! 97: #else !USG ! 98: ttbuf.sg_flags = ANYP|CBREAK|TANDEM; ! 99: #endif USG ! 100: ret = ioctl(Ifn, TCSETA, &ttbuf); ! 101: ASSERT(ret >= 0, "STTY FAILED", "", ret); ! 102: } ! 103: fsig = signal(SIGALRM, falarm); ! 104: /* give the other side time to perform its ioctl; ! 105: * otherwise it may flush out the first data this ! 106: * side is about to send. ! 107: */ ! 108: sleep(2); ! 109: return SUCCESS; ! 110: } ! 111: ! 112: fturnoff() ! 113: { ! 114: (void) signal(SIGALRM, fsig); ! 115: return SUCCESS; ! 116: } ! 117: ! 118: fwrmsg(type, str, fn) ! 119: register char *str; ! 120: int fn; ! 121: char type; ! 122: { ! 123: register char *s; ! 124: char bufr[MAXMSGLEN]; ! 125: ! 126: s = bufr; ! 127: *s++ = type; ! 128: while (*str) ! 129: *s++ = *str++; ! 130: if (*(s-1) == '\n') ! 131: s--; ! 132: *s++ = '\r'; ! 133: *s = 0; ! 134: (void) write(fn, bufr, s - bufr); ! 135: return SUCCESS; ! 136: } ! 137: ! 138: frdmsg(str, fn) ! 139: register char *str; ! 140: register int fn; ! 141: { ! 142: register char *smax; ! 143: ! 144: if (setjmp(Ffailbuf)) ! 145: return FAIL; ! 146: smax = str + MAXMSGLEN - 1; ! 147: (void) alarm(2*MAXMSGTIME); ! 148: for (;;) { ! 149: if (read(fn, str, 1) <= 0) ! 150: goto msgerr; ! 151: *str &= 0177; ! 152: if (*str == '\r') ! 153: break; ! 154: if (*str < ' ') { ! 155: continue; ! 156: } ! 157: if (str++ >= smax) ! 158: goto msgerr; ! 159: } ! 160: *str = '\0'; ! 161: (void) alarm(0); ! 162: return SUCCESS; ! 163: msgerr: ! 164: (void) alarm(0); ! 165: return FAIL; ! 166: } ! 167: ! 168: fwrdata(fp1, fn) ! 169: FILE *fp1; ! 170: int fn; ! 171: { ! 172: register int alen, ret; ! 173: register char *obp; ! 174: char ack, ibuf[MAXMSGLEN]; ! 175: int flen, mil, retries = 0; ! 176: long abytes, fbytes; ! 177: struct timeb t1, t2; ! 178: ! 179: ret = FAIL; ! 180: retry: ! 181: fchksum = 0xffff; ! 182: abytes = fbytes = 0L; ! 183: ack = '\0'; ! 184: #ifdef USG ! 185: time(&t1.time); ! 186: t1.millitm = 0; ! 187: #else !USG ! 188: ftime(&t1); ! 189: #endif !USG ! 190: do { ! 191: alen = fwrblk(fn, fp1, &flen); ! 192: fbytes += flen; ! 193: if (alen <= 0) { ! 194: abytes -= alen; ! 195: goto acct; ! 196: } ! 197: abytes += alen; ! 198: } while (!feof(fp1) && !ferror(fp1)); ! 199: DEBUG(8, "\nchecksum: %04x\n", fchksum); ! 200: if (frdmsg(ibuf, fn) != FAIL) { ! 201: if ((ack = ibuf[0]) == 'G') ! 202: ret = SUCCESS; ! 203: DEBUG(4, "ack - '%c'\n", ack); ! 204: } ! 205: acct: ! 206: #ifdef USG ! 207: time(&t2.time); ! 208: t2.millitm = 0; ! 209: #else !USG ! 210: ftime(&t2); ! 211: #endif !USG ! 212: Now = t2; ! 213: t2.time -= t1.time; ! 214: mil = t2.millitm - t1.millitm; ! 215: if (mil < 0) { ! 216: --t2.time; ! 217: mil += 1000; ! 218: } ! 219: sprintf(ibuf, "sent data %ld bytes %ld.%02d secs", ! 220: fbytes, (long)t2.time, mil / 10); ! 221: sysacct(abytes, t2.time); ! 222: if (retries > 0) ! 223: sprintf(&ibuf[strlen(ibuf)], ", %d retries", retries); ! 224: DEBUG(1, "%s\n", ibuf); ! 225: syslog(ibuf); ! 226: if (ack == 'R') { ! 227: DEBUG(4, "RETRY:\n", 0); ! 228: fseek(fp1, 0L, 0); ! 229: retries++; ! 230: goto retry; ! 231: } ! 232: #ifdef SYSACCT ! 233: if (ret == FAIL) ! 234: sysaccf(NULL); /* force accounting */ ! 235: #endif SYSACCT ! 236: return ret; ! 237: } ! 238: ! 239: /* max. attempts to retransmit a file: */ ! 240: #define MAXRETRIES (fbytes < 10000L ? 2 : 1) ! 241: ! 242: frddata(fn, fp2) ! 243: register int fn; ! 244: register FILE *fp2; ! 245: { ! 246: register int flen; ! 247: register char eof; ! 248: char ibuf[FIBUFSIZ]; ! 249: int ret, mil, retries = 0; ! 250: long alen, abytes, fbytes; ! 251: struct timeb t1, t2; ! 252: ! 253: ret = FAIL; ! 254: retry: ! 255: fchksum = 0xffff; ! 256: abytes = fbytes = 0L; ! 257: #ifdef USG ! 258: time(&t1.time); ! 259: t1.millitm = 0; ! 260: #else !USG ! 261: ftime(&t1); ! 262: #endif !USG ! 263: do { ! 264: flen = frdblk(ibuf, fn, &alen); ! 265: abytes += alen; ! 266: if (flen < 0) ! 267: goto acct; ! 268: if (eof = flen > FIBUFSIZ) ! 269: flen -= FIBUFSIZ + 1; ! 270: fbytes += flen; ! 271: if (fwrite(ibuf, sizeof (char), flen, fp2) != flen) ! 272: goto acct; ! 273: } while (!eof); ! 274: ret = SUCCESS; ! 275: acct: ! 276: #ifdef USG ! 277: time(&t2.time); ! 278: t2.millitm = 0; ! 279: #else !USG ! 280: ftime(&t2); ! 281: #endif !USG ! 282: Now = t2; ! 283: t2.time -= t1.time; ! 284: mil = t2.millitm - t1.millitm; ! 285: if (mil < 0) { ! 286: --t2.time; ! 287: mil += 1000; ! 288: } ! 289: sprintf(ibuf, "received data %ld bytes %ld.%02d secs", ! 290: fbytes, (long)t2.time, mil/10); ! 291: if (retries > 0) ! 292: sprintf(&ibuf[strlen(ibuf)]," %d retries", retries); ! 293: sysacct(abytes, t2.time); ! 294: DEBUG(1, "%s\n", ibuf); ! 295: syslog(ibuf); ! 296: if (ret == FAIL) { ! 297: if (retries++ < MAXRETRIES) { ! 298: DEBUG(8, "send ack: 'R'\n", 0); ! 299: fwrmsg('R', "", fn); ! 300: fseek(fp2, 0L, 0); ! 301: DEBUG(4, "RETRY:\n", 0); ! 302: goto retry; ! 303: } ! 304: DEBUG(8, "send ack: 'Q'\n", 0); ! 305: fwrmsg('Q', "", fn); ! 306: #ifdef SYSACCT ! 307: sysaccf(NULL); /* force accounting */ ! 308: #endif SYSACCT ! 309: } ! 310: else { ! 311: DEBUG(8, "send ack: 'G'\n", 0); ! 312: fwrmsg('G', "", fn); ! 313: } ! 314: return ret; ! 315: } ! 316: ! 317: static ! 318: frdbuf(blk, len, fn) ! 319: register char *blk; ! 320: register int len; ! 321: register int fn; ! 322: { ! 323: static int ret = FIBUFSIZ / 2; ! 324: ! 325: if (setjmp(Ffailbuf)) ! 326: return FAIL; ! 327: (void) alarm(MAXMSGTIME); ! 328: ret = read(fn, blk, len); ! 329: alarm(0); ! 330: return ret <= 0 ? FAIL : ret; ! 331: } ! 332: ! 333: #if !defined(BSD4_2) && !defined(USG) ! 334: /* call ultouch every TC calls to either frdblk or fwrblk */ ! 335: #define TC 20 ! 336: static int tc = TC; ! 337: #endif !defined(BSD4_2) && !defined(USG) ! 338: ! 339: /* Byte conversion: ! 340: * ! 341: * from pre to ! 342: * 000-037 172 100-137 ! 343: * 040-171 040-171 ! 344: * 172-177 173 072-077 ! 345: * 200-237 174 100-137 ! 346: * 240-371 175 040-171 ! 347: * 372-377 176 072-077 ! 348: */ ! 349: ! 350: static ! 351: fwrblk(fn, fp, lenp) ! 352: int fn; ! 353: register FILE *fp; ! 354: int *lenp; ! 355: { ! 356: register char *op; ! 357: register int c, sum, nl, len; ! 358: char obuf[FOBUFSIZ + 8]; ! 359: int ret; ! 360: ! 361: #if !defined(BSD4_2) && !defined(USG) ! 362: /* call ultouch occasionally */ ! 363: if (--tc < 0) { ! 364: tc = TC; ! 365: ultouch(); ! 366: } ! 367: #endif !defined(BSD4_2) && !defined(USG) ! 368: op = obuf; ! 369: nl = 0; ! 370: len = 0; ! 371: sum = fchksum; ! 372: while ((c = getc(fp)) != EOF) { ! 373: len++; ! 374: if (sum & 0x8000) { ! 375: sum <<= 1; ! 376: sum++; ! 377: } else ! 378: sum <<= 1; ! 379: sum += c; ! 380: sum &= 0xffff; ! 381: if (c & 0200) { ! 382: c &= 0177; ! 383: if (c < 040) { ! 384: *op++ = '\174'; ! 385: *op++ = c + 0100; ! 386: } else ! 387: if (c <= 0171) { ! 388: *op++ = '\175'; ! 389: *op++ = c; ! 390: } ! 391: else { ! 392: *op++ = '\176'; ! 393: *op++ = c - 0100; ! 394: } ! 395: nl += 2; ! 396: } else { ! 397: if (c < 040) { ! 398: *op++ = '\172'; ! 399: *op++ = c + 0100; ! 400: nl += 2; ! 401: } else ! 402: if (c <= 0171) { ! 403: *op++ = c; ! 404: nl++; ! 405: } else { ! 406: *op++ = '\173'; ! 407: *op++ = c - 0100; ! 408: nl += 2; ! 409: } ! 410: } ! 411: if (nl >= FOBUFSIZ - 1) { ! 412: /* ! 413: * peek at next char, see if it will fit ! 414: */ ! 415: c = getc(fp); ! 416: if (c == EOF) ! 417: break; ! 418: (void) ungetc(c, fp); ! 419: if (nl >= FOBUFSIZ || c < 040 || c > 0171) ! 420: goto writeit; ! 421: } ! 422: } ! 423: /* ! 424: * At EOF - append checksum, there is space for it... ! 425: */ ! 426: sprintf(op, "\176\176%04x\r", sum); ! 427: nl += strlen(op); ! 428: writeit: ! 429: *lenp = len; ! 430: fchksum = sum; ! 431: DEBUG(8, "%d/", len); ! 432: DEBUG(8, "%d,", nl); ! 433: ret = write(fn, obuf, nl); ! 434: return ret == nl ? nl : ret < 0 ? 0 : -ret; ! 435: } ! 436: ! 437: static ! 438: frdblk(ip, fn, rlen) ! 439: register char *ip; ! 440: int fn; ! 441: long *rlen; ! 442: { ! 443: register char *op, c; ! 444: register int sum, len, nl; ! 445: char buf[5], *erbp = ip; ! 446: int i; ! 447: static char special = 0; ! 448: ! 449: #if !defined(BSD4_2) && !defined(USG) ! 450: /* call ultouch occasionally */ ! 451: if (--tc < 0) { ! 452: tc = TC; ! 453: ultouch(); ! 454: } ! 455: #endif !defined(BSD4_2) && !defined(USG) ! 456: if ((len = frdbuf(ip, FIBUFSIZ, fn)) == FAIL) { ! 457: *rlen = 0; ! 458: goto dcorr; ! 459: } ! 460: *rlen = len; ! 461: DEBUG(8, "%d/", len); ! 462: op = ip; ! 463: nl = 0; ! 464: sum = fchksum; ! 465: do { ! 466: if ((*ip &= 0177) >= '\172') { ! 467: if (special) { ! 468: DEBUG(8, "%d", nl); ! 469: special = 0; ! 470: op = buf; ! 471: if (*ip++ != '\176' || (i = --len) > 5) ! 472: goto dcorr; ! 473: while (i--) ! 474: *op++ = *ip++ & 0177; ! 475: while (len < 5) { ! 476: i = frdbuf(&buf[len], 5 - len, fn); ! 477: if (i == FAIL) { ! 478: len = FAIL; ! 479: goto dcorr; ! 480: } ! 481: DEBUG(8, ",%d", i); ! 482: len += i; ! 483: *rlen += i; ! 484: while (i--) ! 485: *op++ &= 0177; ! 486: } ! 487: if (buf[4] != '\r') ! 488: goto dcorr; ! 489: sscanf(buf, "%4x", &fchksum); ! 490: DEBUG(8, "\nchecksum: %04x\n", sum); ! 491: if (fchksum == sum) ! 492: return FIBUFSIZ + 1 + nl; ! 493: else { ! 494: DEBUG(8, "\n", 0); ! 495: DEBUG(4, "Bad checksum\n", 0); ! 496: return FAIL; ! 497: } ! 498: } ! 499: special = *ip++; ! 500: } else { ! 501: if (*ip < '\040') { ! 502: /* error: shouldn't get control chars */ ! 503: goto dcorr; ! 504: } ! 505: switch (special) { ! 506: case 0: ! 507: c = *ip++; ! 508: break; ! 509: case '\172': ! 510: c = *ip++ - 0100; ! 511: break; ! 512: case '\173': ! 513: c = *ip++ + 0100; ! 514: break; ! 515: case '\174': ! 516: c = *ip++ + 0100; ! 517: break; ! 518: case '\175': ! 519: c = *ip++ + 0200; ! 520: break; ! 521: case '\176': ! 522: c = *ip++ + 0300; ! 523: break; ! 524: } ! 525: *op++ = c; ! 526: if (sum & 0x8000) { ! 527: sum <<= 1; ! 528: sum++; ! 529: } else ! 530: sum <<= 1; ! 531: sum += c & 0377; ! 532: sum &= 0xffff; ! 533: special = 0; ! 534: nl++; ! 535: } ! 536: } while (--len); ! 537: fchksum = sum; ! 538: DEBUG(8, "%d,", nl); ! 539: return nl; ! 540: dcorr: ! 541: DEBUG(8, "\n", 0); ! 542: DEBUG(4, "Data corrupted\n", 0); ! 543: while (len != FAIL) { ! 544: if ((len = frdbuf(erbp, FIBUFSIZ, fn)) != FAIL) ! 545: *rlen += len; ! 546: } ! 547: return FAIL; ! 548: } ! 549:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.