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