|
|
1.1 root 1: /* C K C F N 2 -- System-independent Kermit protocol support functions... */
2:
3: /* ...Part 2 (continued from ckcfns.c) */
4:
5: /*
6: Author: Frank da Cruz ([email protected], [email protected]),
7: Columbia University Center for Computing Activities.
8: First released January 1985.
9: Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New
10: York. Permission is granted to any individual or institution to use this
11: software as long as it is not sold for profit. This copyright notice must be
12: retained. This software may not be included in commercial products without
13: written permission of Columbia University.
14: */
15: /*
16: Note -- if you change this file, please amend the version number and date at
17: the top of ckcfns.c accordingly.
18: */
19:
20: #include "ckcsym.h" /* Compilation options */
21: #include "ckcdeb.h" /* Debugging and other symbols */
22: #include "ckcasc.h" /* ASCII symbols */
23: #include "ckcker.h" /* Kermit symbols */
24: #include "ckcxla.h" /* Translation */
25:
26: #ifdef TCPSOCKET /* For TELNET business in spack() */
27: #ifndef NP_TELNET
28: #define NP_TELNET 1
29: extern int tn_nlm, ttnproto;
30: #endif /* NP_TELNET */
31: #endif /* TCPSOCKET */
32:
33: #ifdef DYNAMIC
34: extern struct pktinfo *s_pkt; /* array of pktinfo structures */
35: extern struct pktinfo *r_pkt; /* array of pktinfo structures */
36: #else
37: extern struct pktinfo s_pkt[]; /* array of pktinfo structures */
38: extern struct pktinfo r_pkt[]; /* array of pktinfo structures */
39: #endif /* DYNAMIC */
40:
41: extern int sseqtbl[], rseqtbl[], sbufuse[], sacktbl[], wslots, winlo, sbufnum;
42:
43: extern int ttprty; /* from ckutio.c */
44: extern int autopar;
45:
46: extern int spsiz, spmax, rpsiz, timint, timef, npad, ebq, ebqflg;
47: extern int rpt, rptq, rptflg, capas, spsizf, en_fin, tsecs, network, flow;
48: extern int pktnum, sndtyp, bctr, bctu, bctl, rsn, rln, maxtry, size;
49: extern int osize, maxsize, spktl, rpktl, nfils, stdouf, warn, parity;
50: extern int turn, turnch, delay, displa, pktlog, tralog, seslog, xflg, mypadn;
51: extern int hcflg, local, server, cxseen, czseen;
52: extern int nakstate, quiet, success, xitsta, what;
53: extern int spackets, rpackets, timeouts, retrans, crunched, urpsiz;
54:
55: extern long filcnt, ffc, flci, flco, tlci, tlco, tfc, speed;
56:
57: extern char *cmarg, *cmarg2, filnam[], *hlptxt;
58:
59: extern CHAR padch, mypadc, eol, seol, ctlq, myctlq, sstate;
60: extern CHAR *recpkt, *data, encbuf[], myinit[];
61: extern CHAR *srvptr, stchr, mystch, *rdatap;
62: extern CHAR padbuf[];
63: #ifdef DYNAMIC
64: extern CHAR *srvcmd;
65: #else
66: extern CHAR srvcmd[];
67: #endif /* DYNAMIC */
68:
69: int numerrs = 0; /* (PWP) total number packet errors so far */
70:
71: static CHAR partab[] = { /* Even parity table for dopar(). */
72: (CHAR) '\000', /* ANSI C casts '\ooo' constants */
73: (CHAR) '\201', /* to signed char, so we have to */
74: (CHAR) '\202', /* cast back to unsigned char... */
75: (CHAR) '\003',
76: (CHAR) '\204',
77: (CHAR) '\005',
78: (CHAR) '\006',
79: (CHAR) '\207',
80: (CHAR) '\210',
81: (CHAR) '\011',
82: (CHAR) '\012',
83: (CHAR) '\213',
84: (CHAR) '\014',
85: (CHAR) '\215',
86: (CHAR) '\216',
87: (CHAR) '\017',
88: (CHAR) '\220',
89: (CHAR) '\021',
90: (CHAR) '\022',
91: (CHAR) '\223',
92: (CHAR) '\024',
93: (CHAR) '\225',
94: (CHAR) '\226',
95: (CHAR) '\027',
96: (CHAR) '\030',
97: (CHAR) '\231',
98: (CHAR) '\232',
99: (CHAR) '\033',
100: (CHAR) '\234',
101: (CHAR) '\035',
102: (CHAR) '\036',
103: (CHAR) '\237',
104: (CHAR) '\240',
105: (CHAR) '\041',
106: (CHAR) '\042',
107: (CHAR) '\243',
108: (CHAR) '\044',
109: (CHAR) '\245',
110: (CHAR) '\246',
111: (CHAR) '\047',
112: (CHAR) '\050',
113: (CHAR) '\251',
114: (CHAR) '\252',
115: (CHAR) '\053',
116: (CHAR) '\254',
117: (CHAR) '\055',
118: (CHAR) '\056',
119: (CHAR) '\257',
120: (CHAR) '\060',
121: (CHAR) '\261',
122: (CHAR) '\262',
123: (CHAR) '\063',
124: (CHAR) '\264',
125: (CHAR) '\065',
126: (CHAR) '\066',
127: (CHAR) '\267',
128: (CHAR) '\270',
129: (CHAR) '\071',
130: (CHAR) '\072',
131: (CHAR) '\273',
132: (CHAR) '\074',
133: (CHAR) '\275',
134: (CHAR) '\276',
135: (CHAR) '\077',
136: (CHAR) '\300',
137: (CHAR) '\101',
138: (CHAR) '\102',
139: (CHAR) '\303',
140: (CHAR) '\104',
141: (CHAR) '\305',
142: (CHAR) '\306',
143: (CHAR) '\107',
144: (CHAR) '\110',
145: (CHAR) '\311',
146: (CHAR) '\312',
147: (CHAR) '\113',
148: (CHAR) '\314',
149: (CHAR) '\115',
150: (CHAR) '\116',
151: (CHAR) '\317',
152: (CHAR) '\120',
153: (CHAR) '\321',
154: (CHAR) '\322',
155: (CHAR) '\123',
156: (CHAR) '\324',
157: (CHAR) '\125',
158: (CHAR) '\126',
159: (CHAR) '\327',
160: (CHAR) '\330',
161: (CHAR) '\131',
162: (CHAR) '\132',
163: (CHAR) '\333',
164: (CHAR) '\134',
165: (CHAR) '\335',
166: (CHAR) '\336',
167: (CHAR) '\137',
168: (CHAR) '\140',
169: (CHAR) '\341',
170: (CHAR) '\342',
171: (CHAR) '\143',
172: (CHAR) '\344',
173: (CHAR) '\145',
174: (CHAR) '\146',
175: (CHAR) '\347',
176: (CHAR) '\350',
177: (CHAR) '\151',
178: (CHAR) '\152',
179: (CHAR) '\353',
180: (CHAR) '\154',
181: (CHAR) '\355',
182: (CHAR) '\356',
183: (CHAR) '\157',
184: (CHAR) '\360',
185: (CHAR) '\161',
186: (CHAR) '\162',
187: (CHAR) '\363',
188: (CHAR) '\164',
189: (CHAR) '\365',
190: (CHAR) '\366',
191: (CHAR) '\167',
192: (CHAR) '\170',
193: (CHAR) '\371',
194: (CHAR) '\372',
195: (CHAR) '\173',
196: (CHAR) '\374',
197: (CHAR) '\175',
198: (CHAR) '\176',
199: (CHAR) '\377'
200: };
201:
202: /* CRC generation tables */
203:
204: static long crcta[16] = { 0L, 010201L, 020402L, 030603L, 041004L,
205: 051205L, 061406L, 071607L, 0102010L, 0112211L, 0122412L, 0132613L, 0143014L,
206: 0153215L, 0163416L, 0173617L };
207:
208: static long crctb[16] = { 0L, 010611L, 021422L, 031233L, 043044L,
209: 053655L, 062466L, 072277L, 0106110L, 0116701L, 0127532L, 0137323L, 0145154L,
210: 0155745L, 0164576L, 0174367L };
211:
212:
213: /* I N P U T -- Attempt to read packet number 'pktnum'. */
214:
215: /*
216: This is the function that feeds input to Kermit's finite state machine,
217: in the form of a character in the range 32-126, normally a packet type
218: (uppercase letter) or pseudo-packet-type (lowercase letter).
219:
220: If a special start state is in effect, that state is returned as if it were
221: the type of an incoming packet. Otherwise:
222:
223: (fill in...)
224: */
225:
226: int
227: input() {
228: int type;
229: int x = 0, y, k;
230:
231: debug(F101,"input sstate","",sstate);
232: debug(F101," nakstate","",nakstate);
233: debug(F000," sndtyp","",sndtyp);
234:
235: while (1) { /* Big loop... */
236:
237: if (sstate != 0) { /* If a start state is in effect, */
238: type = sstate; /* return it like a packet type, */
239: sstate = 0; /* and then nullify it. */
240: numerrs = 0; /* (PWP) no errors so far */
241: return(type);
242: }
243:
244: if (nakstate) { /* This section for file receiver. */
245:
246: if (wslots > 1) { /* If we're doing windows, */
247: x = rseqtbl[winlo]; /* see if desired packet already in. */
248: debug(F101," winlo","",winlo);
249: debug(F101," rseqtbl[winlo]","",rseqtbl[winlo]);
250: if (x > -1) { /* Already there? */
251: if (r_pkt[x].pk_seq == winlo) { /* (double check) */
252: rsn = winlo; /* Yes, return its info */
253: debug(F101,"input return pre-stashed packet","",rsn);
254: dumprbuf();
255: rdatap = r_pkt[x].pk_adr; /* like rpack would do. */
256: rln = (int)strlen((char *) rdatap);
257: type = r_pkt[x].pk_typ;
258: break;
259: }
260: }
261: }
262: type = rpack(); /* Try to read a packet. */
263: debug(F111,"input recv",(char *) rdatap,(int) type);
264: while (type == 'e') { /* Handle echoes */
265: debug(F000,"echo discarded","",type);
266: type = rpack();
267: }
268: if (type < -1) return('q'); /* Ctrl-C */
269: if (type < 0) { /* Receive window full */
270: /* Another thing to do here would be to delete */
271: /* the highest packet and NAK winlo. But that */
272: /* shouldn't be necessary since the other Kermit */
273: /* should not have sent a packet outside the window. */
274: debug(F101,"rpack receive window full","",0);
275: dumprbuf();
276: errpkt((CHAR *)"Receive window full.");
277: strcpy((char *)recpkt,"Receive window full.");
278: type = 'E';
279: break;
280: }
281: dumprbuf();
282:
283: if (chkint() < 0) { /* Check for console interrupts. */
284: errpkt((CHAR *)"User cancelled.");
285: strcpy((char *)recpkt,"User cancelled.");
286: type = 'E';
287: break;
288: }
289: if (type == 'E') {
290: debug(F101,"input got E, nakstate","",nakstate);
291: break; /* Error packet */
292: }
293: if (type == 'Q') { /* Crunched packet. */
294: crunched++;
295: numerrs++;
296: if (nack(winlo) < 0) { /* Request resend of window-low.. */
297: debug(F101,"input sent too many naks","",winlo);
298: errpkt((CHAR *)"Too many retries.");
299: strcpy((char *)recpkt,"Sent too many NAKs.");
300: type = 'E';
301: break;
302: } else continue;
303: }
304: if (type == 'T') { /* Timeout */
305: #ifdef BULKNAKS
306: int z;
307: #endif
308: timeouts++;
309: debug(F101,"input receive-state timeout, winlo","",winlo);
310: #ifdef BULKNAKS
311: z = winlo + wslots; /* NAK all unACK'd packets */
312: if (z > 63) z -= 64;
313: debug(F101,"input sending bulk NAKs, winlo","",winlo);
314: for (x = winlo; (x != z) && ttchk() == 0; x++) {
315: if (x < 0 || x > 63) break;
316: if (rseqtbl[x] < 0) {
317: if (nack(x) < 0) {
318: debug(F101,"input sent too many naks","",winlo);
319: errpkt((CHAR *)"Too many retries.");
320: strcpy(recpkt,"Sent too many NAKs.");
321: type = 'E';
322: break;
323: }
324: }
325: }
326: #else /* NAK only the packet at window-low */
327: debug(F101,"input sending NAK for winlo","",winlo);
328: if (nack(winlo) < 0) {
329: debug(F101,"input sent too many naks","",winlo);
330: errpkt((CHAR *)"Too many retries.");
331: strcpy((char *)recpkt,"Sent too many NAKs.");
332: type = 'E';
333: break;
334: }
335: #endif /* BULKNAKS */
336: continue;
337: }
338:
339: /* Got the packet we want, done. */
340:
341: if (rsn == winlo) {
342: debug(F101,"input rsn=winlo","",rsn);
343: break;
344: }
345:
346: /* Got a packet out of order. */
347:
348: debug(F101,"input recv got packet out of order","",rsn);
349: k = rseqtbl[rsn]; /* Get window slot of this packet. */
350: debug(F101,"input recv rseqtbl[rsn]","",k);
351: if (k < 0) {
352: debug(F101,"input recv can't find index for rcvd pkt","",rsn);
353: errpkt((CHAR *)"internal error number 21");
354: strcpy((char *)recpkt,"Sliding windows protocol error.");
355: type = 'E';
356: break;
357: }
358: y = chkwin(rsn,winlo,wslots); /* See what window it's in. */
359: debug(F101,"input recv chkwin","",y);
360: if (y == 1) { /* Previous window. */
361: #ifdef COMMENT
362: ackn(rsn); /* Send empty ACK */
363: #else
364: resend(rsn);
365: #endif /* COMMENT */
366: freerpkt(rsn); /* Get rid of received packet */
367: continue;
368: } else { /* In this window or out of range */
369: if (y < 0) /* If out of range entirely, */
370: freerpkt(rsn); /* release its buffer */
371: /*
372: We have received a packet, but not the one we want. If we do nothing,
373: we could be in for a lengthy timeout/retry cycle. It would seem to
374: make sense to send a NAK for the most desired packet (winlo). But
375: consider this scenario: a packet arrived damaged so we NAK'd it above;
376: then packets winlo+1, winlo+2, ... winlo+n arrive, each one making us
377: send a NAK for winlo, so the other Kermit gets n NAKs for winlo, and
378: either would have to resend it n times, or if n > retry limit, give up
379: because of too many retries. So we compromise: If a packet arrives
380: that is not the most desired packet (winlo), we NAK winlo, BUT ONLY IF
381: it has not been NAK'd before.
382: */
383: if (s_pkt[k].pk_rtr == 0) { /* Have we been here before? */
384: if (nack(winlo) < 0) { /* No, NAK winlo. */
385: errpkt((CHAR *)"Too many retries."); /* Too many */
386: strcpy((char *)recpkt,"Timed out."); /* Give up */
387: type = 'E';
388: break;
389: } else continue;
390: } else continue;
391: }
392: /*!!!*/
393: } else { /* Otherwise file sender... */
394:
395: if (wslots > 1) { /* Packet at winlo already ACK'd? */
396: if (sacktbl[winlo]) { /* If so, */
397: sacktbl[winlo] = 0; /* Turn off the ACK'd flag */
398: winlo = (winlo + 1) % 64; /* Rotate the window */
399: type = 'Y'; /* And return ACK */
400: debug(F101,
401: "input send returning pre-stashed ACK","",
402: winlo-1);
403: break;
404: }
405: }
406: type = rpack(); /* Try to read an acknowledgement */
407: debug(F111,"input send",(char *) rdatap,(int) type);
408: while (type == 'e') { /* Handle echoes */
409: debug(F000,"echo discarded","",type);
410: type = rpack();
411: }
412: if (type == -2) return('q');
413: if (type == -1) {
414: errpkt((CHAR *)"Internal error number 18");
415: debug(F101," wslots","",wslots);
416: debug(F101," winlo","",winlo);
417: debug(F101," pktnum","",pktnum);
418: dumprbuf();
419: strcpy((char *)recpkt,"Can't allocate receive buffer");
420: type = 'E';
421: break;
422: }
423: dumprbuf(); /* debugging */
424:
425: if (chkint() < 0) { /* Check for console interrupts. */
426: errpkt((CHAR *)"User cancelled.");
427: strcpy((char *)recpkt,"User cancelled.");
428: return(type = 'E');
429: }
430:
431: /* got a packet */
432:
433: if (type == 'E') {
434: debug(F101,"input send got E, nakstate","",nakstate);
435: break; /* Error packet */
436: }
437: if (type == 'Q') { /* Crunched packet */
438: crunched++; /* For statistics */
439: numerrs++; /* For packet resizing */
440: x = resend(winlo); /* Resend window-low */
441: if (x < 0) {
442: type = 'E';
443: errpkt(recpkt);
444: break;
445: }
446: continue;
447: }
448: if (type == 'T') { /* Timeout waiting for ACKs. */
449: timeouts++; /* Count it */
450: numerrs++; /* Count an error too */
451: debug(F101,"input send state timeout, winlo","",winlo);
452:
453: /* Retransmit the oldest un-ACK'd packet. */
454:
455: debug(F101,"input send resending winlo","",winlo);
456: if (resend(winlo) < 0) { /* Check retries */
457: debug(F101,"input send too many resends","",maxtry);
458: errpkt(recpkt);
459: return(type = 'E');
460: }
461: continue;
462: }
463:
464: /* Got an actual normal packet */
465:
466: y = chkwin(rsn,winlo,wslots); /* Is it in the window? */
467: debug(F101,"input send rsn","",rsn);
468: debug(F101,"input send winlo","",winlo);
469: debug(F101,"input send chkwin","",y);
470: if (type == 'Y') { /* Got an ACK */
471: if (y == 0) { /* In current window */
472: x = sseqtbl[rsn]; /* Mark the packet as ACK'd */
473: if (x > -1) s_pkt[x].pk_flg++; /* (old way) */
474: sacktbl[rsn]++; /* (new way) */
475: /*
476: NOTE: The following statement frees the buffer of the ACK we just got.
477: But the upper layers still need the data, like if it's the ACK to an I,
478: S, F, D, Z, or just about any kind of packet. So for now, freerbuf()
479: deallocates the buffer, but does not erase the data or destroy the pointer
480: to it. There's no other single place where these receive buffers can be
481: correctly freed (?) ...
482: */
483: freerpkt(rsn); /* Free the ACK's buffer */
484: freesbuf(rsn); /* *** Free the sent packet's buffer */
485: if (rsn == winlo) { /* Got the one we want */
486: sacktbl[winlo] = 0;
487: winlo = (winlo + 1) % 64;
488: debug(F101,"input send rotated send window","",winlo);
489: break; /* Return the ACK */
490: } else {
491: debug(F101,"input send mark pkt","",rsn);
492: continue; /* Otherwise go read another packet */
493: }
494: } else { /* ACK not in window, ignore */
495: debug(F101,"input send ACK out of window","",rsn);
496: freerpkt(rsn);
497: continue;
498: }
499: }
500: if (type == 'N') { /* NAK */
501: numerrs++; /* Count an error */
502: debug(F101,"input send NAK","",rsn);
503: freerpkt(rsn); /* Free buffer where NAK lies. */
504: if (y == 0) { /* In current window */
505: debug(F100," in window","",0);
506: k = sseqtbl[rsn]; /* Get pointer to NAK'd packet. */
507: x = 0;
508: if (k < 0 || (k > -1 && s_pkt[k].pk_typ == ' ')) {
509: x = resend(winlo); /* Packet we haven't sent yet. */
510: } else {
511: x = resend(rsn); /* Resend requested packet. */
512: }
513: if (x < 0) { /* Resend error is fatal. */
514: type = 'E';
515: errpkt(recpkt);
516: break;
517: } else continue; /* Resend ok, go read another packet */
518: } else if ((rsn == (pktnum + 1) % 64)) { /* NAK for next pkt */
519: if (wslots > 1) {
520: debug( F101,"NAK for next packet, windowing","",rsn);
521: x = resend(winlo); /* Resend window-low */
522: if (x < 0) {
523: type = 'E';
524: errpkt(recpkt);
525: break;
526: }
527: continue; /* Go back and read another pkt */
528: }
529: debug(F101,"NAK for next packet, no windowing","",rsn);
530: x = (rsn == 0) ? 63 : rsn - 1;
531: if (x == 0 && (sndtyp == 'S' || sndtyp == 'I')) {
532: resend(0); /* ACK for S or I packet missing */
533: continue; /* so resend it. */
534: } /* Else, treat NAK(n+1) as ACK(n) */
535: if ((x = sseqtbl[x]) > -1) {
536: sacktbl[x]++; /* (new way) */
537: s_pkt[x].pk_flg++; /* (old way) */
538: }
539: type = 'Y'; /* Treat it as ACK for last pkt */
540: break;
541: } else if (y > 0) { /* NAK for pkt we can't resend */
542: debug(F101," NAK out of window","",rsn); /* bad... */
543: type = 'E';
544: errpkt((CHAR *)"NAK out of window");
545: strcpy((char *)recpkt,"NAK out of window.");
546: break;
547: } else continue; /* Ignore other NAKs */
548: } /* End of file-sender NAK handler */
549:
550: if (rsn == winlo) { /* Not ACK, NAK, timeout, etc. */
551: debug(F000,"input send unexpected type","",type);
552: break;
553: }
554: } /* End of file-sender section */
555: } /* End of input() loop */
556: if (wslots == 1) {
557: debug(F100,"input about to flush","",0);
558: ttflui(); /* Got what we want, clear input buffer. */
559: }
560: if (!nakstate) /* When sending */
561: rcalcpsz(); /* recalculate size every packet */
562: debug(F000,"input returning type","",type);
563: return(type); /* Success, return packet type. */
564: }
565:
566: /* D O P A R -- Add an appropriate parity bit to a character */
567:
568: /*
569: (PWP) this is still used in the Mac terminal emulator, so we have to keep it
570: */
571: CHAR
572: #ifdef CK_ANSIC
573: dopar(register CHAR ch)
574: #else
575: dopar(ch) register CHAR ch;
576: #endif /* CK_ANSIC */
577: {
578: register unsigned int a;
579: if (!parity) return((CHAR) (ch & 255)); else a = ch & 127;
580: switch (parity) {
581: case 'e': return(partab[a]); /* Even */
582: case 'm': return((CHAR) (a | 128)); /* Mark */
583: case 'o': return((CHAR) (partab[a] ^ 128)); /* Odd */
584: case 's': return((CHAR) a); /* Space */
585: default: return((CHAR) a); /* Something illegal */
586: }
587: }
588:
589: #ifdef PARSENSE
590: /* P A R C H K -- Check if Kermit packet has parity */
591:
592: /*
593: Call with s = pointer to packet, start = packet start character, n = length.
594: Returns 0 if packet has no parity, -1 on error, or, if packet has parity:
595: 'e' for even, 'o' for odd, 'm' for mark. Space parity cannot be sensed.
596: So a return value of 0 really means either space or none.
597: Returns -2 if parity has already been checked during this protocol operation.
598: */
599: int
600: #ifdef CK_ANSIC
601: parchk(CHAR *s, CHAR start, int n)
602: #else
603: parchk(s,start,n) CHAR *s, start; int n;
604: #endif /* CK_ANSIC */
605: /* parchk */ {
606: CHAR s0, s1, s2, s3;
607:
608: debug(F101,"parchk n","",n);
609: debug(F101,"parchk start","",start);
610:
611: s0 = s[0] & 0x7f; /* Mark field (usually Ctrl-A) */
612:
613: if (s0 != start || n < 5) return(-1); /* Not a valid packet */
614:
615: /* Look at packet control fields, which never have 8th bit set */
616: /* First check for no parity, most common case. */
617:
618: if (((s[0] | s[1] | s[2] | s[3]) & 0x80) == 0)
619: return(0); /* No parity or space parity */
620:
621: /* Check for mark parity */
622:
623: if (((s[0] & s[1] & s[2] & s[3]) & 0x80) == 0x80)
624: return('m'); /* Mark parity */
625:
626: /* Packet has some kind of parity */
627: /* Make 7-bit copies of control fields */
628:
629: s1 = s[1] & 0x7f; /* LEN */
630: s2 = s[2] & 0x7f; /* SEQ */
631: s3 = s[3] & 0x7f; /* TYPE */
632:
633: /* Check for even parity */
634:
635: if ((s[0] == partab[s0]) &&
636: (s[1] == partab[s1]) &&
637: (s[2] == partab[s2]) &&
638: (s[3] == partab[s3]))
639: return('e');
640:
641: /* Check for odd parity */
642:
643: if ((s[0] != partab[s0]) &&
644: (s[1] != partab[s1]) &&
645: (s[2] != partab[s2]) &&
646: (s[3] != partab[s3]))
647: return('o');
648:
649: /* Otherwise it's probably line noise. Let checksum calculation catch it. */
650:
651: return(-1);
652: }
653: #endif /* PARSENSE */
654:
655: /*
656: Check to make sure timeout intervals are long enough to allow maximum
657: length packets to get through before the timer goes off. If not, the
658: timeout interval is adjusted upwards.
659:
660: This routine is called at the beginning of a transaction, before we
661: know anything about the delay characteristics of the line. It works
662: only for serial communication devices; it trusts the speed reported by
663: the operating system.
664:
665: Call with a timout interval. Returns it, adjusted if necessary.
666: */
667: int
668: chktimo(timo,flag) int timo, flag; {
669: long cps, z; int x, y;
670: debug(F101,"chktimo timo","",timo); /* Timeout before adjustment */
671: debug(F101,"chktimo flag","",flag);
672:
673: if (flag) /* Don't change timeout if user */
674: return(timo); /* gave SET SEND TIMEOUT command. */
675: debug(F101,"chktimo spmax","",spmax);
676: debug(F101,"chktimo urpsiz","",urpsiz);
677:
678: speed = ttgspd(); /* Get current speed. */
679: if (speed > 0L && !network) {
680: cps = speed / 10L; /* Convert to chars per second */
681: if (cps > 0L) {
682: long plen; /* Maximum of send and rcv pkt size */
683: z = cps * (long) timo; /* Chars per timeout interval */
684: z -= z / 10L; /* Less 10 percent */
685: plen = spmax;
686: if (urpsiz > spmax) plen = urpsiz;
687: debug(F101,"chktimo plen","",plen);
688: if (z < plen) { /* Compare with packet size */
689: x = (int) ((long) plen / cps); /* Adjust if necessary */
690: y = x / 10; /* Add 10 percent for safety */
691: if (y < 2) y = 2; /* Or 2 seconds, whichever is more */
692: x += y;
693: if (x > timo) /* If this is greater than current */
694: timo = x; /* timeout, change the timeout */
695: debug(F101,"chktimo new timo","",timo);
696: }
697: }
698: }
699: return(timo);
700: }
701:
702: /* S P A C K -- Construct and send a packet */
703:
704: /*
705: spack() sends a packet of the given type, sequence number n, with len data
706: characters pointed to by d, in either a regular or extended- length packet,
707: depending on len. Returns the number of bytes actually sent, or else -1
708: upon failure. Uses global npad, padch, mystch, bctu, data. Leaves packet
709: fully built and null-terminated for later retransmission by resend().
710: Updates global sndpktl (send-packet length).
711:
712: NOTE: The global pointer "data" is assumed to point into the 7th position
713: of a character array (presumably in packet buffer for the current packet).
714: It was used by getpkt() to build the packet data field. spack() fills in
715: the header to the left of the data pointer (the data pointer is defined
716: in getsbuf() in ckcfn3.c). If the address "d" is the same as "data", then
717: the packet's data field has been built "in place" and need not be copied.
718: */
719: int
720: #ifdef CK_ANSIC
721: spack(char pkttyp, int n, int len, CHAR *d)
722: #else
723: spack(pkttyp,n,len,d) char pkttyp; int n, len; CHAR *d;
724: #endif /* CK_ANSIC */
725: /* spack */ {
726: register int i;
727: int j, k, lp, longpkt, copy;
728: register CHAR *cp, *mydata;
729: unsigned crc;
730:
731: debug(F101,"spack n","",n);
732: debug(F111," data",data,data);
733: debug(F101," d","",d);
734: debug(F101," len","",len);
735:
736: copy = (d != data); /* Flag whether data must be copied */
737: longpkt = (len + bctl + 2) > 94; /* Decide whether it's a long packet */
738: mydata = data - 7 + (longpkt ? 0 : 3); /* Starting position of header */
739: debug(F101," mydata","",mydata);
740:
741: k = sseqtbl[n]; /* Packet structure info for pkt n */
742: debug(F101," sseqtbl[n]","",k);
743: if (k < 0) {
744: debug(F101,"spack sending packet out of window","",n);
745: } else { /* Record packet info */
746: s_pkt[k].pk_adr = mydata; /* Remember address of packet. */
747: s_pkt[k].pk_seq = n; /* Record sequence number */
748: s_pkt[k].pk_typ = pkttyp; /* Record packet type */
749: }
750:
751: spktl = 0; /* Initialize length of this packet */
752: i = 0; /* and position in packet. */
753:
754: /* Now fill the packet */
755:
756: mydata[i++] = mystch; /* MARK */
757: lp = i++; /* Position of LEN, fill in later */
758:
759: mydata[i++] = tochar(n); /* SEQ field */
760: mydata[i++] = pkttyp; /* TYPE field */
761: j = len + bctl; /* Length of data + block check */
762: if (longpkt) { /* Long packet? */
763: int x; /* Work around SCO Xenix/286 */
764: x = 95; /* compiler bug... */
765: x = j / 95;
766: mydata[lp] = tochar(0); /* Yes, set LEN to zero */
767: mydata[i++] = tochar(x); /* High part */
768: mydata[i++] = tochar(j % 95); /* Low part */
769: mydata[i] = '\0'; /* Header checksum */
770: mydata[i++] = tochar(chk1(mydata+lp));
771: } else mydata[lp] = tochar(j+2); /* Normal LEN */
772:
773: if (copy) /* Data field built in place? */
774: for ( ; len--; i++) mydata[i] = *d++; /* No, must copy. */
775: else /* Otherwise, */
776: i += len; /* Just skip past data field. */
777: mydata[i] = '\0'; /* Null-terminate for checksum calc. */
778:
779: switch (bctu) { /* Block check */
780: case 1: /* 1 = 6-bit chksum */
781: mydata[i++] = tochar(chk1(mydata+lp));
782: break;
783: case 2: /* 2 = 12-bit chksum */
784: j = chk2(mydata+lp);
785: mydata[i++] = (unsigned)tochar((j >> 6) & 077);
786: mydata[i++] = (unsigned)tochar(j & 077);
787: break;
788: case 3: /* 3 = 16-bit CRC */
789: crc = chk3(mydata+lp);
790: mydata[i++] = (unsigned)tochar(((crc & 0170000)) >> 12);
791: mydata[i++] = (unsigned)tochar((crc >> 6) & 077);
792: mydata[i++] = (unsigned)tochar(crc & 077);
793: break;
794: case 4: /* 2 = 12-bit chksum, blank-free */
795: j = chk2(mydata+lp);
796: mydata[i++] =
797: (unsigned)(tochar((unsigned)(((j >> 6) & 077) + 1)));
798: mydata[i++] = (unsigned)(tochar((unsigned)((j & 077) + 1)));
799: break;
800: }
801: mydata[i++] = seol; /* End of line (packet terminator) */
802: #ifdef TCPSOCKET
803: /*
804: If TELNET connection and packet terminator is carriage return,
805: we must stuff either LF or NUL, according to SET TELNET NEWLINE-MODE
806: (tn_nlm), to meet the TELNET specification.
807: */
808: if (network && ttnproto == NP_TELNET && seol == CR)
809: mydata[i++] = tn_nlm ? LF : NUL;
810: #endif /* TCPSOCKET */
811: mydata[i] = '\0'; /* Terminate string */
812: logpkt('s',n,mydata); /* Log packet */
813:
814: /* (PWP) add the parity quickly at the end */
815: switch (parity) {
816: case 'e': /* Even */
817: for (cp = &mydata[i-1]; cp >= mydata; cp--)
818: *cp = partab[*cp];
819: break;
820: case 'm': /* Mark */
821: for (cp = &mydata[i-1]; cp >= mydata; cp--)
822: *cp |= 128;
823: break;
824: case 'o': /* Odd */
825: for (cp = &mydata[i-1]; cp >= mydata; cp--)
826: *cp = partab[*cp] ^ 128;
827: break;
828: case 's': /* Space */
829: for (cp = &mydata[i-1]; cp >= mydata; cp--)
830: *cp &= 127;
831: break;
832: }
833: if (npad) ttol(padbuf,npad); /* Send any padding */
834: spktl = i; /* Remember packet length */
835: s_pkt[k].pk_len = spktl; /* also in packet info structure */
836: if (ttol(mydata,spktl) < 0) return(-1); /* Send the packet */
837: sndtyp = pkttyp; /* Remember packet type for echos */
838: spackets++; /* Count it. */
839: flco += spktl; /* Count the characters */
840: tlco += spktl; /* for statistics... */
841: dumpsbuf(); /* Dump send buffers to debug log */
842: screen(SCR_PT,pkttyp,(long)n,(char *)mydata); /* Update screen */
843: return(spktl); /* Return length */
844: }
845:
846: /* C H K 1 -- Compute a type-1 Kermit 6-bit checksum. */
847:
848: int
849: chk1(pkt) register CHAR *pkt; {
850: register unsigned int chk;
851: chk = chk2(pkt);
852: chk = (((chk & 0300) >> 6) + chk) & 077;
853: return((int) chk);
854: }
855:
856: /* C H K 2 -- Compute the numeric sum of all the bytes in the packet. */
857:
858: unsigned int
859: chk2(pkt) register CHAR *pkt; {
860: register long chk; register unsigned int m;
861: m = (parity) ? 0177 : 0377;
862: for (chk = 0; *pkt != '\0'; pkt++)
863: chk += *pkt & m;
864: return((unsigned int) (chk & 07777));
865: }
866:
867:
868: /* C H K 3 -- Compute a type-3 Kermit block check. */
869: /*
870: Calculate the 16-bit CRC-CCITT of a null-terminated string using a lookup
871: table. Assumes the argument string contains no embedded nulls.
872: */
873: unsigned int
874: chk3(pkt) register CHAR *pkt; {
875: register long c, crc;
876: register unsigned int m;
877: m = (parity) ? 0177 : 0377;
878: for (crc = 0; *pkt != '\0'; pkt++) {
879: c = crc ^ (long)(*pkt & m);
880: crc = (crc >> 8) ^ (crcta[(c & 0xF0) >> 4] ^ crctb[c & 0x0F]);
881: }
882: return((unsigned int) (crc & 0xFFFF));
883: }
884:
885: int
886: nxtpkt() { /* Called by file sender */
887: int j, n;
888:
889: debug(F101,"nxtpkt pktnum","",pktnum);
890: debug(F101,"nxtpkt winlo ","",winlo);
891: n = (pktnum + 1) % 64; /* Increment packet number mod 64 */
892: #ifdef COMMENT
893: /*
894: Suggested by Alan Grieg. A packet can be sent out of window in
895: circumstances involving acks received out of order, ... Have to think
896: about this...
897: */
898: if (chkwin(n,winlo,wslots)) {
899: debug(F101,"nxtpkt n not in window","",n);
900: return(-1);
901: }
902: #endif
903: j = getsbuf(n); /* Get a buffer for packet n */
904: if (j < 0) {
905: debug(F101,"nxtpkt can't getsbuf","",j);
906: return(-1);
907: }
908: pktnum = n;
909: debug(F101,"nxtpkt bumped pktnum to","",pktnum);
910: return(0);
911: }
912:
913: /* Functions for sending ACKs and NAKs */
914:
915: /* Note, we should only ACK the packet at window-low (winlo) */
916: /* However, if an old packet arrives again (e.g. because the ACK we sent */
917: /* earlier was lost), we ACK it again. */
918:
919: int
920: ack() { /* Acknowledge the current packet. */
921: return(ackns(winlo,(CHAR *)""));
922: }
923:
924: int
925: ackns(n,s) int n; CHAR *s; { /* Acknowledge packet n */
926: int j, k;
927: debug(F111,"ackns",s,n);
928:
929: k = rseqtbl[n]; /* First find received packet n. */
930: debug(F101,"ackns k","",k);
931: #ifdef COMMENT
932: /* No need to set ACK'd bit, because we're gonna free the buffer now */
933: if (k > -1) /* If in window */
934: s_pkt[k].pk_flg++; /* mark the ack'd bit. */
935: else
936: debug(F101,"ackns can't set ack'd bit","",k);
937: #endif
938: freesbuf(n); /* Free current send-buffer, if any */
939: if ((j = getsbuf(n)) < 0) {
940: /* This can happen if we have to re-ACK an old packet that has */
941: /* already left the window. It does no harm. */
942: debug(F101,"ackns can't getsbuf","",n);
943: }
944: spack('Y',n,(int)strlen((char *)s),s); /* Now send it. */
945: debug(F101,"ackns winlo","",winlo);
946: debug(F101,"ackns n","",n);
947: if (n == winlo) { /* If we're acking winlo */
948: if (k > -1)
949: freerbuf(k); /* don't need it any more */
950: if (j > -1)
951: freesbuf(j); /* and don't need to keep ACK either */
952: winlo = (winlo + 1) % 64;
953: }
954: return(0);
955: }
956:
957: int
958: ackn(n) int n; { /* Send ACK for packet number n */
959: return(ackns(n,(CHAR *)""));
960: }
961:
962: int
963: ack1(s) CHAR *s; { /* Send an ACK with data. */
964: debug(F110,"ack1",(char *) s,0);
965: return(ackns(winlo, s));
966: }
967:
968: /* N A C K -- Send a Negative ACKnowledgment. */
969: /*
970: Call with the packet number, n, to be NAK'd.
971: Returns -1 if that packet has been NAK'd too many times, otherwise 0.
972: Btw, it is not right to return 0 under error conditions. This is
973: done because the -1 code is used for cancelling the file transfer.
974: More work is needed here.
975: */
976: int
977: nack(n) int n; {
978: int i;
979:
980: if (n < 0 || n > 63) {
981: debug(F101,"nack bad pkt num","",n);
982: return(0);
983: } else debug(F101,"nack","",n);
984: if ((i = sseqtbl[n]) < 0) { /* If necessary */
985: if (getsbuf(n) < 0) { /* get a buffer for this NAK */
986: debug(F101,"nack can't getsbuf","",n);
987: return(0);
988: } else i = sseqtbl[n]; /* New slot number */
989: }
990: if (s_pkt[i].pk_rtr++ > maxtry) /* How many times have we done this? */
991: return(-1); /* Too many... */
992:
993: /* Note, don't free this buffer. Eventually an ACK will come, and that */
994: /* will set it free. If not, well, it's back to ground zero anyway... */
995:
996: spack('N',n,0,(CHAR *) ""); /* NAKs never have data. */
997: return(0);
998: }
999:
1000: /*
1001: * (PWP) recalculate the optimal packet length in the face of errors.
1002: * This is a modified version of the algorithm by John Chandler in Kermit/370,
1003: * see "Dynamic Packet Size Control", Kermit News, V2 #1, June 1988.
1004: *
1005: * This implementation minimizes the total overhead equation, which is
1006: *
1007: * Total chars = file_chars + (header_len * num_packs)
1008: * + (errors * (header_len + packet_len))
1009: *
1010: * Differentiate with respect to number of chars, solve for packet_len, get:
1011: *
1012: * packet_len = sqrt (file_chars * header_len / errors)
1013: */
1014:
1015: /*
1016: (FDC) New super-simple algorithm. If there was an error in the most recent
1017: packet exchange, cut the send-packet size in half, down to a minimum of 20.
1018: If there was no error, increase the size by 5/4, up to the maximum negotiated
1019: length. Seems to be much more responsive than previous algorithm, which took
1020: forever to recover the original packet length, and it also went crazy under
1021: certain conditions.
1022:
1023: Here's another idea for packet length resizing that keeps a history of the
1024: last n packets. Push a 1 into the left end of an n-bit shift register if the
1025: current packet is good, otherwise push a zero. The current n-bit value, w, of
1026: this register is a weighted sum of the noise hits for the last n packets, with
1027: the most recent weighing the most. The current packet length is some function
1028: of w and the negotiated packet length, like:
1029:
1030: (2^n - w) / (2^n) * (negotiated length)
1031:
1032: If the present resizing method causes problems, think about this one a little
1033: more.
1034: */
1035: VOID
1036: rcalcpsz() {
1037:
1038: #ifdef COMMENT
1039: /* Old way */
1040: register long x, q;
1041: if (numerrs == 0) return; /* bounds check just in case */
1042:
1043: /* overhead on a data packet is npad+5+bctr, plus 3 if extended packet */
1044: /* an ACK is 5+bctr */
1045:
1046: /* first set x = per packet overhead */
1047: if (wslots > 1)
1048: x = (long) (npad+5+bctr); /* only the packet, don't count the ack */
1049: else
1050: x = (long) (npad+5+3+bctr+5+bctr);
1051:
1052: /* then set x = packet length ** 2 */
1053: x = x * ( ffc / (long) numerrs); /* careful of overflow */
1054:
1055: /* calculate the long integer sqrt(x) quickly */
1056: q = 500;
1057: q = (q + x/q) >> 1;
1058: q = (q + x/q) >> 1;
1059: q = (q + x/q) >> 1;
1060: q = (q + x/q) >> 1; /* should converge in about 4 steps */
1061: if ((q > 94) && (q < 130)) /* break-even point for long packets */
1062: q = 94;
1063: if (q > spmax) q = spmax; /* maximum bounds */
1064: if (q < 10) q = 10; /* minimum bounds */
1065: spsiz = q; /* set new send packet size */
1066: debug(F101,"rcalcpsiz","",q);
1067: #else
1068: /* New way */
1069: if (spackets < 3) return;
1070: debug(F101,"rcalcpsiz numerrs","",numerrs);
1071: debug(F101,"rcalcpsiz spsiz","",spsiz);
1072: if (numerrs)
1073: spsiz = spsiz / 2;
1074: else
1075: spsiz = (spsiz / 4) * 5;
1076: if (spsiz < 20) spsiz = 20;
1077: if (spsiz > spmax) spsiz = spmax;
1078: debug(F101,"rcalcpsiz new spsiz","",spsiz);
1079: numerrs = 0;
1080: return;
1081: #endif
1082: }
1083:
1084: /* R E S E N D -- Retransmit packet n. */
1085:
1086: /*
1087: Returns 0 or positive on success (the number of retries for packet n).
1088: On failure, returns a negative number, and an error message is placed
1089: in recpkt.
1090: */
1091: int
1092: resend(n) int n; { /* Send packet n again. */
1093: int j, k;
1094:
1095: debug(F101,"resend seq","",n);
1096:
1097: k = chkwin(n,winlo,wslots); /* See if packet in current window */
1098: j = -1; /* Assume it's lost */
1099: if (k == 0) j = sseqtbl[n]; /* See if we still have a copy of it */
1100: if (k != 0 || j < 0) { /* If not.... */
1101: if (nakstate && k == 1) {
1102: /*
1103: Packet n is in the previous window and we are the file receiver.
1104: We already sent the ACK and deallocated its buffer so we can't just
1105: retransmit the ACK. Rather than give up, we try some tricks...
1106: */
1107: if (n == 0 && spackets < 63 && myinit[0]) { /* ACK to Send-Init */
1108: /*
1109: If the packet number is 0, and we're at the beginning of a protocol
1110: operation (spackets < 63), then we have to resend the ACK to an I or S
1111: packet, complete with parameters in the data field. So we take a chance and
1112: send a copy of the parameters in an ACK packet with block check type 1.
1113: */
1114: int bctlsav; /* Temporary storage */
1115: int bctusav;
1116: bctlsav = bctl; /* Save current block check length */
1117: bctusav = bctu; /* and type */
1118: bctu = bctl = 1; /* Set block check to 1 */
1119: spack('Y',0,(int)strlen((char *)myinit),(CHAR *)myinit);
1120: logpkt('#',n,(CHAR *)"<reconstructed>"); /* Log it */
1121: bctu = bctusav; /* Restore block check type */
1122: bctl = bctlsav; /* and length */
1123:
1124: } else { /* Not the first packet */
1125: /*
1126: It's not the first packet of the protocol operation. It's some other packet
1127: that we have already ACK'd and forgotten about. So we take a chance and
1128: send an empty ACK using the current block-check type. Usually this will
1129: work out OK (like when acking Data packets), and no great harm will be done
1130: if it was some other kind of packet (F, etc). If we are requesting an
1131: interruption of the file transfer, the flags are still set, so we'll catch
1132: up on the next packet.
1133: */
1134: spack('Y',n,0,(CHAR *) "");
1135: logpkt('#',n,(CHAR *)"<faith>"); /* Log it */
1136: }
1137: retrans++;
1138: screen(SCR_PT,'%',(long)pktnum,"(resend)");
1139: return(0);
1140: } else {
1141: /*
1142: Packet number is not in current or previous window. We seem to hit this
1143: code occasionally at the beginning of a transaction, for apparently no good
1144: reason. Let's just log it for debugging, send nothing, and try to proceed
1145: with the protocol rather than killing it.
1146: */
1147: debug(F101,"RESEND PKT NOT IN WINDOW","",n);
1148: debug(F101,"RESEND k","",k);
1149: #ifdef COMMENT
1150: sprintf((char *)recpkt,
1151: " resend error: NIW, n=%d, k=%d.",n,k);
1152: return(-2);
1153: #else
1154: return(0);
1155: #endif /* COMMENT */
1156: }
1157: }
1158:
1159: /* OK, it's in the window and it's not lost. */
1160:
1161: debug(F101,"resend pktinfo index","",k);
1162:
1163: if (s_pkt[j].pk_rtr++ > maxtry) { /* Found it but over retry limit */
1164: strcpy((char *)recpkt,"Too many retries.");
1165: return(-1);
1166: }
1167: debug(F101," retry","",s_pkt[j].pk_rtr); /* OK so far */
1168: dumpsbuf(); /* (debugging) */
1169: if (s_pkt[j].pk_typ == ' ') { /* Incompletely formed packet */
1170: if (nakstate) { /* (This shouldn't happen any more) */
1171: nack(n);
1172: retrans++;
1173: screen(SCR_PT,'%',(long)pktnum,"(resend)");
1174: return(s_pkt[j].pk_rtr);
1175: } else { /* No packet to resend! */
1176: #ifdef COMMENT
1177: /*
1178: This happened (once) while sending a file with 2 window slots and typing
1179: X to the sender to cancel the file. But since we're cancelling anyway,
1180: no need to give a scary message.
1181: */
1182: sprintf((char *)recpkt,
1183: "resend logic error: NPS, n=%d, j=%d.",n,j);
1184: return(-2);
1185: #else
1186: /* Just ignore it. */
1187: return(0);
1188: #endif /* COMMENT */
1189: }
1190: }
1191: ttol(s_pkt[j].pk_adr,s_pkt[j].pk_len); /* Everything ok, send the packet */
1192: retrans++; /* Count a retransmission */
1193: screen(SCR_PT,'%',(long)pktnum,"(resend)"); /* Tell user about resend */
1194: logpkt('S',n,s_pkt[j].pk_adr); /* Log the resent packet */
1195: return(s_pkt[j].pk_rtr); /* Return the number of retries. */
1196: }
1197:
1198: int
1199: errpkt(reason) CHAR *reason; { /* Send an error packet. */
1200: int x, y;
1201: encstr(reason);
1202: y = spack('E',pktnum,size,encbuf+7);
1203: x = quiet; quiet = 1; /* Close files silently. */
1204: clsif(); clsof(1);
1205: quiet = x;
1206: #ifdef COMMENT
1207: screen(SCR_TC,0,0l,"");
1208: #endif /* COMMENT */
1209: if (what < W_CONNECT)
1210: xitsta |= what; /* Remember what failed. */
1211: success = 0;
1212: return(y);
1213: }
1214:
1215: /* scmd() -- Send a packet of the given type */
1216:
1217: int
1218: #ifdef CK_ANSIC
1219: scmd(char t, CHAR *dat)
1220: #else
1221: scmd(t,dat) char t; CHAR *dat;
1222: #endif /* CK_ANSIC */
1223: /* scmd */ {
1224: encstr(dat); /* Encode the command string */
1225: spack(t,pktnum,size,(CHAR *)(encbuf+7));
1226: return(0);
1227: }
1228:
1229: VOID
1230: srinit() { /* Send R (GET) packet */
1231: encstr((CHAR *)cmarg); /* Encode the filename. */
1232: spack('R',pktnum,size,encbuf+7); /* Send the packet. */
1233: }
1234:
1235: /* R P A C K -- Read a Packet */
1236:
1237: /*
1238: rpack reads a packet and returns the packet type, or else Q if the
1239: packet was invalid, or T if a timeout occurred. Upon successful return, sets
1240: the values of global rsn (received sequence number), rln (received
1241: data length), and rdatap (pointer to null-terminated data field).
1242: */
1243: int
1244: rpack() {
1245: register int i, j, x, lp; /* Local variables */
1246: int k, type, chklen;
1247: unsigned crc;
1248: CHAR pbc[4]; /* Packet block check */
1249: CHAR *sohp; /* Pointer to SOH */
1250: CHAR e; /* Packet end character */
1251:
1252: debug(F101,"entering rpack, pktnum","",pktnum);
1253: k = getrbuf(); /* Get a new packet input buffer. */
1254: debug(F101,"rpack getrbuf","",k);
1255: if (k < 0) return(-1); /* Return like this if none free. */
1256: recpkt = r_pkt[k].bf_adr;
1257: *recpkt = '\0'; /* Clear receive buffer. */
1258: sohp = recpkt; /* Initialize pointers to it. */
1259: rdatap = recpkt;
1260: rsn = rln = -1; /* In case of failure. */
1261: e = (turn) ? turnch : eol; /* Use any handshake char for eol */
1262:
1263: /* Try to get a "line". */
1264:
1265: #ifdef PARSENSE
1266: #ifdef UNIX
1267: /*
1268: So far the final turn argument is only for ck[uvd]tio.c. Should be added
1269: to the others too. (turn == handshake character.)
1270: */
1271: j = ttinl(recpkt,r_pkt[k].bf_len - 1,timint,e,stchr,turn);
1272: #else
1273: #ifdef VMS
1274: j = ttinl(recpkt,r_pkt[k].bf_len - 1,timint,e,stchr,turn);
1275: #else
1276: #ifdef datageneral
1277: j = ttinl(recpkt,r_pkt[k].bf_len - 1,timint,e,stchr,turn);
1278: #else
1279: j = ttinl(recpkt,r_pkt[k].bf_len - 1,timint,e,stchr);
1280: #endif /* datageneral */
1281: #endif /* VMS */
1282: #endif /* UNIX */
1283: if (parity != ttprty) autopar = 1;
1284: parity = ttprty;
1285: #else
1286: j = ttinl(recpkt,r_pkt[k].bf_len - 1,timint,e);
1287: #endif /* PARSENSE */
1288: if (j < 0) {
1289: debug(F101,"rpack: ttinl fails","",j); /* Otherwise, */
1290: freerbuf(k); /* Free this buffer */
1291: if (j < -1) { /* Bail out if ^C^C typed. */
1292: debug(F101,"rpack ^C server","",server);
1293: debug(F101,"rpack ^C en_fin","",en_fin);
1294: if (server == 0) return(j); /* But not if in server mode */
1295: else if (en_fin) return(j); /* with DISABLE FINISH */
1296: }
1297: if (nakstate) /* call it a timeout. */
1298: screen(SCR_PT,'T',(long)winlo,"");
1299: else
1300: screen(SCR_PT,'T',(long)pktnum,"");
1301: logpkt('r',-1,(CHAR *)"<timeout>");
1302: if (flow == 1) ttoc(XON); /* In case of Xoff blockage. */
1303: return('T');
1304: }
1305: rpktl = j;
1306: tlci += j; /* All OK, Count the characters. */
1307: flci += j;
1308:
1309: #ifndef PARSENSE
1310: /* THEN eliminate this loop... */
1311: for (i = 0; (recpkt[i] != stchr) && (i < j); i++)
1312: sohp++; /* Find mark */
1313: if (i++ >= j) { /* Didn't find it. */
1314: logpkt('r',-1,"<timeout>");
1315: freerbuf(k);
1316: return('T');
1317: }
1318: #else
1319: i = 1;
1320: #endif /* PARSENSE */
1321:
1322: rpackets++;
1323: lp = i; /* Remember LEN position. */
1324: if ((j = xunchar(recpkt[i++])) == 0) {
1325: if ((j = lp+5) > MAXRP) return('Q'); /* Long packet */
1326: x = recpkt[j]; /* Header checksum. */
1327: recpkt[j] = '\0'; /* Calculate & compare. */
1328: if (xunchar(x) != chk1(recpkt+lp)) {
1329: freerbuf(k);
1330: logpkt('r',-1,(CHAR *)"<crunched:hdr>");
1331: return('Q');
1332: }
1333: recpkt[j] = x; /* Checksum ok, put it back. */
1334: rln = xunchar(recpkt[j-2]) * 95 + xunchar(recpkt[j-1]) - bctl;
1335: j = 3; /* Data offset. */
1336: } else if (j < 3) {
1337: debug(F101,"rpack packet length less than 3","",j);
1338: freerbuf(k);
1339: logpkt('r',-1,(CHAR *)"<crunched:len>");
1340: return('Q');
1341: } else {
1342: rln = j - bctl - 2; /* Regular packet */
1343: j = 0; /* No extended header */
1344: }
1345: rsn = xunchar(recpkt[i++]); /* Sequence number */
1346: logpkt('r',rsn,sohp);
1347: if (rsn < 0 || rsn > 63) {
1348: debug(F101,"rpack bad sequence number","",rsn);
1349: freerbuf(k);
1350: logpkt('r',rsn,(CHAR *)"<crunched:seq>");
1351: return('Q');
1352: }
1353: /*
1354: If this packet has the same type as the packet just sent, assume it is
1355: an echo and ignore it. Don't even bother with the block check calculation:
1356: even if the packet is corrupted, we don't want to NAK an echoed packet.
1357: (And we certainly don't want to NAK an ACK or NAK!)
1358: */
1359: type = recpkt[i++]; /* Get packet's TYPE field */
1360: if (type == sndtyp || (nakstate && (type == 'N' /* || type == 'Y' */ ))) {
1361: debug(F000,"rpack echo","",type); /* If it's an echo */
1362: freerbuf(k); /* Free this buffer */
1363: logpkt('#',rsn,(CHAR *)"<echo:ignored>");
1364: return('e'); /* return special (lowercase) code */
1365: }
1366: /*
1367: Separate the data from the block check, accounting for the case where
1368: a packet was retransmitted after the block check switched.
1369: */
1370: if (type == 'I' || type == 'S') { /* I & S packets always have type 1 */
1371: chklen = 1;
1372: rln = rln + bctl - 1;
1373: } else if (type == 'N') { /* A NAK packet never has data */
1374: chklen = xunchar(recpkt[lp]) - 2;
1375: rln = rln + bctl - chklen;
1376: } else chklen = bctl;
1377: debug(F101,"rpack bctl","",bctl);
1378: debug(F101,"rpack chklen","",chklen);
1379:
1380: i += j; /* Buffer index of DATA field */
1381: rdatap = recpkt+i; /* Pointer to DATA field */
1382: if ((j = rln + i) > r_pkt[k].bf_len ) { /* Make sure it fits */
1383: debug(F101,"packet sticks out too far","",j);
1384: freerbuf(k);
1385: logpkt('r',rsn,(CHAR *)"<overflow>");
1386: return('Q');
1387: }
1388:
1389: for (x = 0; x < chklen; x++) /* Copy the block check */
1390: pbc[x] = recpkt[j+x];
1391: pbc[x] = '\0'; /* Null-terminate block check string */
1392: recpkt[j] = '\0'; /* and the packet DATA field. */
1393:
1394: if (chklen == 2 && bctu == 4) { /* Adjust for Blank-Free-2 */
1395: chklen = 4; /* (chklen is now a misnomer...) */
1396: debug(F100,"rpack block check B","",0);
1397: }
1398: switch (chklen) { /* Check the block check */
1399: case 1: /* Type 1, 6-bit checksum */
1400: if (xunchar(*pbc) != chk1(recpkt+lp)) {
1401: debug(F110,"checked chars",recpkt+lp,0);
1402: debug(F101,"block check","",(int) xunchar(*pbc));
1403: debug(F101,"should be","",chk1(recpkt+lp));
1404: freerbuf(k);
1405: logpkt('r',-1,(CHAR *)"<crunched:chk1>");
1406: return('Q');
1407: }
1408: break;
1409: case 2: /* Type 2, 12-bit checksum */
1410: x = xunchar(*pbc) << 6 | xunchar(pbc[1]);
1411: if (x != chk2(recpkt+lp)) { /* No match */
1412: if (type == 'E') { /* Allow E packets to have type 1 */
1413: recpkt[j++] = pbc[0];
1414: recpkt[j] = '\0';
1415: if (xunchar(pbc[1]) == chk1(recpkt+lp))
1416: break;
1417: else
1418: recpkt[--j] = '\0';
1419: }
1420: debug(F110,"checked chars",recpkt+lp,0);
1421: debug(F101,"block check","", x);
1422: debug(F101,"should be","", (int) chk2(recpkt+lp));
1423: freerbuf(k);
1424: logpkt('r',-1,(CHAR *)"<crunched:chk2>");
1425: return('Q');
1426: }
1427: break;
1428: case 3: /* Type 3, 16-bit CRC */
1429: crc = (xunchar(pbc[0]) << 12)
1430: | (xunchar(pbc[1]) << 6)
1431: | (xunchar(pbc[2]));
1432: if (crc != chk3(recpkt+lp)) {
1433: if (type == 'E') { /* Allow E packets to have type 1 */
1434: recpkt[j++] = pbc[0];
1435: recpkt[j++] = pbc[1];
1436: recpkt[j] = '\0';
1437: if (xunchar(pbc[2]) == chk1(recpkt+lp))
1438: break;
1439: else { j -=2; recpkt[j] = '\0'; }
1440: }
1441: debug(F110,"checked chars",recpkt+lp,0);
1442: debug(F101,"block check","",xunchar(*pbc));
1443: debug(F101,"should be","",(int) chk3(recpkt+lp));
1444: freerbuf(k);
1445: logpkt('r',-1,(CHAR *)"<crunched:chk3>");
1446: return('Q');
1447: }
1448: break;
1449: case 4: /* Type 4 = Type 2, no blanks. */
1450: x = (unsigned)((xunchar(*pbc) - 1) << 6) |
1451: (unsigned)(xunchar(pbc[1]) - 1);
1452: if (x != chk2(recpkt+lp)) {
1453: if (type == 'E') { /* Allow E packets to have type 1 */
1454: recpkt[j++] = pbc[0];
1455: recpkt[j] = '\0';
1456: if (xunchar(pbc[1]) == chk1(recpkt+lp))
1457: break;
1458: else
1459: recpkt[--j] = '\0';
1460: }
1461: debug(F101,"bad type B block check","",x);
1462: freerbuf(k);
1463: logpkt('r',-1,(CHAR *)"<crunched:chkb>");
1464: return('Q');
1465: }
1466: break;
1467: default: /* Shouldn't happen... */
1468: freerbuf(k);
1469: logpkt('r',-1,(CHAR *)"<crunched:chkx>");
1470: return('Q');
1471: }
1472: debug(F101,"rpack block check OK","",rsn);
1473:
1474: /* Now we can believe the sequence number, and other fields. */
1475: /* Here we violate strict principles of layering, etc, and look at the */
1476: /* packet sequence number. If there's already a packet with the same */
1477: /* number in the window, we remove this one so that the window will not */
1478: /* fill up. */
1479:
1480: if ((x = rseqtbl[rsn]) != -1) { /* Already a packet with this number */
1481: retrans++; /* Count it for statistics */
1482: debug(F101,"rpack got dup","",rsn);
1483: logpkt('r',rsn,(CHAR *)"<duplicate>");
1484: freerbuf(x); /* Free old buffer, keep new packet. */
1485: r_pkt[k].pk_rtr++; /* Count this as a retransmission. */
1486: }
1487:
1488: /* New packet, not seen before, enter it into the receive window. */
1489:
1490: rseqtbl[rsn] = k; /* Make back pointer */
1491: r_pkt[k].pk_seq = rsn; /* Record in packet info structure */
1492: r_pkt[k].pk_typ = type; /* Sequence, type,... */
1493: r_pkt[k].pk_adr = rdatap; /* pointer to data buffer */
1494: screen(SCR_PT,(char)type,(long)rsn,(char *)sohp); /* Update screen */
1495: return(type); /* Return packet type */
1496: }
1497:
1498: /* L O G P K T -- Log packet number n, pointed to by s. */
1499:
1500: /* c = 's' (send) or 'r' (receive) */
1501:
1502: VOID
1503: #ifdef CK_ANSIC
1504: logpkt(char c,int n, CHAR *s)
1505: #else
1506: logpkt(c,n,s) char c; int n; CHAR *s;
1507: #endif /* CK_ANSIC */
1508: /* logpkt */ {
1509: char plog[20];
1510: if (pktlog && *s) {
1511: if (n < 0)
1512: sprintf(plog,"%c-xx-%02d-",c,(gtimer()%60));
1513: else
1514: sprintf(plog,"%c-%02d-%02d-",c,n,(gtimer()%60));
1515: if (zsout(ZPFILE,plog) < 0) pktlog = 0;
1516: else if (zsoutl(ZPFILE,(char *)s) < 0) pktlog = 0;
1517: }
1518: }
1519:
1520: #ifdef TLOG
1521:
1522: /* T S T A T S -- Record statistics in transaction log */
1523:
1524: VOID
1525: tstats() {
1526: char *tp;
1527: ztime(&tp); /* Get time stamp */
1528: tlog(F110,"End of transaction",tp,0L); /* Record it */
1529:
1530: if (filcnt < 1) return; /* If no files, done. */
1531:
1532: /* If multiple files, record character totals for all files */
1533:
1534: if (filcnt > 1) {
1535: tlog(F101," files","",filcnt);
1536: tlog(F101," total file characters ","",tfc);
1537: tlog(F101," communication line in ","",tlci);
1538: tlog(F101," communication line out ","",tlco);
1539: }
1540:
1541: /* Record timing info for one or more files */
1542:
1543: tlog(F101," elapsed time (seconds) ","",(long) tsecs);
1544: if (tsecs > 0) {
1545: long lx;
1546: lx = (tfc * 10L) / (long) tsecs;
1547: tlog(F101," effective data rate ","",lx/10L);
1548: if (speed <= 0L) speed = ttgspd();
1549: if (speed > 0L && speed != 8880L && network == 0) {
1550: lx = (lx * 100L) / speed;
1551: tlog(F101," efficiency (percent) ","",lx);
1552: }
1553: }
1554: tlog(F100,"","",0L); /* Leave a blank line */
1555: }
1556:
1557: /* F S T A T S -- Record file statistics in transaction log */
1558:
1559: VOID
1560: fstats() {
1561: tfc += ffc;
1562: tlog(F100," end of file","",0L);
1563: tlog(F101," file characters ","",ffc);
1564: tlog(F101," communication line in ","",flci);
1565: tlog(F101," communication line out ","",flco);
1566: }
1567: #else /* NOTLOG */
1568: VOID
1569: tstats() {}
1570:
1571: VOID
1572: fstats() {
1573: tfc += ffc;
1574: }
1575: #endif /* TLOG */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.