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