BSD 4_4_Lite2 development
[unix-history] / usr / src / contrib / kermit-5A.188 / ckcfn2.c
CommitLineData
cdd19d13
C
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 (fdc@watsun.cc.columbia.edu, FDCCU@CUVMA.BITNET),
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
29extern int tn_nlm, ttnproto;
30#endif /* NP_TELNET */
31#endif /* TCPSOCKET */
32
33#ifdef DYNAMIC
34extern struct pktinfo *s_pkt; /* array of pktinfo structures */
35extern struct pktinfo *r_pkt; /* array of pktinfo structures */
36#else
37extern struct pktinfo s_pkt[]; /* array of pktinfo structures */
38extern struct pktinfo r_pkt[]; /* array of pktinfo structures */
39#endif /* DYNAMIC */
40
41extern int sseqtbl[], rseqtbl[], sbufuse[], sacktbl[], wslots, winlo, sbufnum;
42
43extern int ttprty; /* from ckutio.c */
44extern int autopar;
45
46extern int spsiz, spmax, rpsiz, timint, timef, npad, ebq, ebqflg;
47extern int rpt, rptq, rptflg, capas, spsizf, en_fin, tsecs, network, flow;
48extern int pktnum, sndtyp, bctr, bctu, bctl, rsn, rln, maxtry, size;
49extern int osize, maxsize, spktl, rpktl, nfils, stdouf, warn, parity;
50extern int turn, turnch, delay, displa, pktlog, tralog, seslog, xflg, mypadn;
51extern int hcflg, local, server, cxseen, czseen;
52extern int nakstate, quiet, success, xitsta, what;
53extern int spackets, rpackets, timeouts, retrans, crunched, urpsiz;
54
55extern long filcnt, ffc, flci, flco, tlci, tlco, tfc, speed;
56
57extern char *cmarg, *cmarg2, filnam[], *hlptxt;
58
59extern CHAR padch, mypadc, eol, seol, ctlq, myctlq, sstate;
60extern CHAR *recpkt, *data, encbuf[], myinit[];
61extern CHAR *srvptr, stchr, mystch, *rdatap;
62extern CHAR padbuf[];
63#ifdef DYNAMIC
64 extern CHAR *srvcmd;
65#else
66 extern CHAR srvcmd[];
67#endif /* DYNAMIC */
68
69int numerrs = 0; /* (PWP) total number packet errors so far */
70
71static 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
204static long crcta[16] = { 0L, 010201L, 020402L, 030603L, 041004L,
205 051205L, 061406L, 071607L, 0102010L, 0112211L, 0122412L, 0132613L, 0143014L,
206 0153215L, 0163416L, 0173617L };
207
208static 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
226int
227input() {
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\f
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*/
571CHAR
572#ifdef CK_ANSIC
573dopar(register CHAR ch)
574#else
575dopar(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*/
599int
600#ifdef CK_ANSIC
601parchk(CHAR *s, CHAR start, int n)
602#else
603parchk(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\f
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*/
667int
668chktimo(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\f
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*/
719int
720#ifdef CK_ANSIC
721spack(char pkttyp, int n, int len, CHAR *d)
722#else
723spack(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\f
846/* C H K 1 -- Compute a type-1 Kermit 6-bit checksum. */
847
848int
849chk1(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
858unsigned int
859chk2(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*/
873unsigned int
874chk3(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\f
885int
886nxtpkt() { /* 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
919int
920ack() { /* Acknowledge the current packet. */
921 return(ackns(winlo,(CHAR *)""));
922}
923
924int
925ackns(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
957int
958ackn(n) int n; { /* Send ACK for packet number n */
959 return(ackns(n,(CHAR *)""));
960}
961
962int
963ack1(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*/
976int
977nack(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*/
1035VOID
1036rcalcpsz() {
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*/
1091int
1092resend(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
1198int
1199errpkt(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
1217int
1218#ifdef CK_ANSIC
1219scmd(char t, CHAR *dat)
1220#else
1221scmd(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
1229VOID
1230srinit() { /* Send R (GET) packet */
1231 encstr((CHAR *)cmarg); /* Encode the filename. */
1232 spack('R',pktnum,size,encbuf+7); /* Send the packet. */
1233}
1234\f
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*/
1243int
1244rpack() {
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
1502VOID
1503#ifdef CK_ANSIC
1504logpkt(char c,int n, CHAR *s)
1505#else
1506logpkt(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
1524VOID
1525tstats() {
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
1559VOID
1560fstats() {
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 */
1568VOID
1569tstats() {}
1570
1571VOID
1572fstats() {
1573 tfc += ffc;
1574}
1575#endif /* TLOG */