|
|
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.