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@columbia.edu>,
7 Columbia University Academic Information Systems, New York City.
8
9 Copyright (C) 1985, 2011,
10 Trustees of Columbia University in the City of New York.
11 All rights reserved. See the C-Kermit COPYING.TXT file or the
12 copyright text in the ckcmai.c module for disclaimer and permissions.
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" /* Compilation options */
20 #include "ckcdeb.h" /* Debugging and other symbols */
21 #include "ckcasc.h" /* ASCII symbols */
22 #include "ckcker.h" /* Kermit symbols */
23 #include "ckcxla.h" /* Translation */
24 #include "ckcnet.h" /* IKS and VMS #define TCPSOCKET */
25 #ifdef TCPSOCKET /* For TELNET business in spack() */
26 extern int tn_nlm, ttnproto, tn_b_nlm;
27 #endif /* TCPSOCKET */
28
29 extern int parity, network, local, interrupted, fatalio, wasclosed;
30
31 int kstartactive = 0; /* Flag for kstart() in a packet */
32
33 static CHAR p_tbl[] = { /* Even parity table for dopar(). */
34 (CHAR) '\000', /* ANSI C casts '\ooo' constants */
35 (CHAR) '\201', /* to signed char, so we have to */
36 (CHAR) '\202', /* cast back to unsigned char... */
37 (CHAR) '\003',
38 (CHAR) '\204',
39 (CHAR) '\005',
40 (CHAR) '\006',
41 (CHAR) '\207',
42 (CHAR) '\210',
43 (CHAR) '\011',
44 (CHAR) '\012',
45 (CHAR) '\213',
46 (CHAR) '\014',
47 (CHAR) '\215',
48 (CHAR) '\216',
49 (CHAR) '\017',
50 (CHAR) '\220',
51 (CHAR) '\021',
52 (CHAR) '\022',
53 (CHAR) '\223',
54 (CHAR) '\024',
55 (CHAR) '\225',
56 (CHAR) '\226',
57 (CHAR) '\027',
58 (CHAR) '\030',
59 (CHAR) '\231',
60 (CHAR) '\232',
61 (CHAR) '\033',
62 (CHAR) '\234',
63 (CHAR) '\035',
64 (CHAR) '\036',
65 (CHAR) '\237',
66 (CHAR) '\240',
67 (CHAR) '\041',
68 (CHAR) '\042',
69 (CHAR) '\243',
70 (CHAR) '\044',
71 (CHAR) '\245',
72 (CHAR) '\246',
73 (CHAR) '\047',
74 (CHAR) '\050',
75 (CHAR) '\251',
76 (CHAR) '\252',
77 (CHAR) '\053',
78 (CHAR) '\254',
79 (CHAR) '\055',
80 (CHAR) '\056',
81 (CHAR) '\257',
82 (CHAR) '\060',
83 (CHAR) '\261',
84 (CHAR) '\262',
85 (CHAR) '\063',
86 (CHAR) '\264',
87 (CHAR) '\065',
88 (CHAR) '\066',
89 (CHAR) '\267',
90 (CHAR) '\270',
91 (CHAR) '\071',
92 (CHAR) '\072',
93 (CHAR) '\273',
94 (CHAR) '\074',
95 (CHAR) '\275',
96 (CHAR) '\276',
97 (CHAR) '\077',
98 (CHAR) '\300',
99 (CHAR) '\101',
100 (CHAR) '\102',
101 (CHAR) '\303',
102 (CHAR) '\104',
103 (CHAR) '\305',
104 (CHAR) '\306',
105 (CHAR) '\107',
106 (CHAR) '\110',
107 (CHAR) '\311',
108 (CHAR) '\312',
109 (CHAR) '\113',
110 (CHAR) '\314',
111 (CHAR) '\115',
112 (CHAR) '\116',
113 (CHAR) '\317',
114 (CHAR) '\120',
115 (CHAR) '\321',
116 (CHAR) '\322',
117 (CHAR) '\123',
118 (CHAR) '\324',
119 (CHAR) '\125',
120 (CHAR) '\126',
121 (CHAR) '\327',
122 (CHAR) '\330',
123 (CHAR) '\131',
124 (CHAR) '\132',
125 (CHAR) '\333',
126 (CHAR) '\134',
127 (CHAR) '\335',
128 (CHAR) '\336',
129 (CHAR) '\137',
130 (CHAR) '\140',
131 (CHAR) '\341',
132 (CHAR) '\342',
133 (CHAR) '\143',
134 (CHAR) '\344',
135 (CHAR) '\145',
136 (CHAR) '\146',
137 (CHAR) '\347',
138 (CHAR) '\350',
139 (CHAR) '\151',
140 (CHAR) '\152',
141 (CHAR) '\353',
142 (CHAR) '\154',
143 (CHAR) '\355',
144 (CHAR) '\356',
145 (CHAR) '\157',
146 (CHAR) '\360',
147 (CHAR) '\161',
148 (CHAR) '\162',
149 (CHAR) '\363',
150 (CHAR) '\164',
151 (CHAR) '\365',
152 (CHAR) '\366',
153 (CHAR) '\167',
154 (CHAR) '\170',
155 (CHAR) '\371',
156 (CHAR) '\372',
157 (CHAR) '\173',
158 (CHAR) '\374',
159 (CHAR) '\175',
160 (CHAR) '\176',
161 (CHAR) '\377'
162 };
163
164 /* D O P A R -- Add an appropriate parity bit to a character */
165
166 CHAR
167 #ifdef CK_ANSIC
dopar(register CHAR ch)168 dopar(register CHAR ch)
169 #else
170 dopar(ch) register CHAR ch;
171 #endif /* CK_ANSIC */
172 {
173 register unsigned int a;
174 if (!parity
175 #ifdef TCPSOCKET
176 || (network && (ttnproto == NP_TELNET) && (TELOPT_ME(TELOPT_BINARY)))
177 #ifndef NOXFER
178 || (!local && sstelnet) /* TELNET BINARY MODE */
179 #endif /* NOXFER */
180 #endif /* TCPSOCKET */
181 ) return((CHAR) (ch & 255)); else a = ch & 127;
182 switch (parity) {
183 case 'e': return(p_tbl[a]); /* Even */
184 case 'm': return((CHAR) (a | 128)); /* Mark */
185 case 'o': return((CHAR) (p_tbl[a] ^ 128)); /* Odd */
186 case 's': return((CHAR) a); /* Space */
187 default: return((CHAR) a); /* Something illegal */
188 }
189 }
190
191 #ifndef NOXFER /* Rest of this file... */
192
193 #define NEWDPL /* New dynamic packet length method */
194
195 #ifdef VMS
196 extern int batch;
197 #else
198 extern int backgrd;
199 #endif /* VMS */
200
201 #ifdef DYNAMIC
202 extern struct pktinfo *s_pkt; /* array of pktinfo structures */
203 extern struct pktinfo *r_pkt; /* array of pktinfo structures */
204 #else
205 extern struct pktinfo s_pkt[]; /* array of pktinfo structures */
206 extern struct pktinfo r_pkt[]; /* array of pktinfo structures */
207 #endif /* DYNAMIC */
208
209 extern int sseqtbl[], rseqtbl[], sbufuse[], sacktbl[], wslots, winlo, wslotn,
210 sbufnum, rbufnum, pktpaus, reliable;
211
212 #ifdef STREAMING
213 static int dontsend = 0;
214 extern int streaming;
215 #endif /* STREAMING */
216
217 extern int ttprty; /* from ck*tio.c */
218 extern int autopar;
219
220 extern int spsiz, spmax, rpsiz, timint, timef, npad, bestlen, maxsend;
221 extern int rpt, rptq, rptflg, capas, spsizf, en_fin, tsecs, flow;
222 extern int pktnum, sndtyp, rcvtyp, bctr, bctu, bctf, bctl, rsn, rln, maxtry;
223 extern int size, osize, maxsize, spktl, rpktl, nfils, stdouf, fsecs;
224 extern int turn, turnch, displa, pktlog, seslog, xflg, mypadn;
225 extern int hcflg, server, cxseen, czseen, discard, slostart;
226 extern int nakstate, quiet, success, xitsta, what, filestatus;
227 extern int spackets, rpackets, timeouts, retrans, crunched, urpsiz;
228 extern int carrier, fdispla, srvidl;
229
230 #ifdef GFTIMER
231 extern CKFLOAT fptsecs, fpfsecs, fpxfsecs;
232 #endif /* GFTIMER */
233
234 extern long filcnt, filrej, speed, filcps, tfcps;
235 extern CK_OFF_T ffc, flci, flco, tlci, tlco, tfc;
236
237 extern char *cmarg, filnam[];
238
239 extern CHAR padch, mypadc, eol, seol, ctlq, sstate;
240 extern CHAR *recpkt, *data, myinit[];
241 extern CHAR *srvptr, stchr, mystch, *rdatap;
242 extern CHAR padbuf[];
243 extern CHAR * epktmsg;
244 extern int epktrcvd, epktsent;
245
246 #ifdef OS2 /* AUTODOWNLOAD parameters */
247 extern int adl_kmode, adl_zmode; /* Match Packet to signal download */
248 extern char * adl_kstr; /* KERMIT Download String */
249 extern char * adl_zstr; /* ZMODEM Download String */
250 #endif /* OS2 */
251
252 #ifdef CK_AUTODL
253 CHAR ksbuf[96] = { NUL, NUL }; /* Autodownload "Kermit Start" buf */
254 #endif /* CK_AUTODL */
255
256 int numerrs = 0; /* Number of packet errors so far */
257 int rcvtimo = 0; /* Timeout for receiving a packet */
258 int idletmo = 0; /* Flag for idle timeout */
259
260 long filcps = 0L; /* CPS most recent file transferred */
261 long tfcps = 0L; /* CPS most recent transaction */
262 long xfsecs = 0L; /* Elapsed time for most recent file */
263 #ifdef GFTIMER
264 CKFLOAT fpxfsecs = 0.0; /* Ditto, but floating point */
265 #endif /* GFTIMER */
266
267 #ifdef CK_TIMERS
268 int rrttbl[64], srttbl[64]; /* Packet timestamp tables */
269 extern int rttflg;
270 #define RTT_SCALE 1000
271 long
272 rttsamples, /* Round trip time samples */
273 rttdelay, /* RTT delay */
274 pktintvl, /* Interpacket arrival time */
275 rttvariance, /* RTT variance */
276 rttstddev; /* RTT standard deviation */
277 #endif /* CK_TIMERS */
278
279 /* CRC generation tables */
280
281 long crcta[16] = { 0L, 010201L, 020402L, 030603L, 041004L,
282 051205L, 061406L, 071607L, 0102010L, 0112211L, 0122412L, 0132613L, 0143014L,
283 0153215L, 0163416L, 0173617L
284 };
285
286 long crctb[16] = { 0L, 010611L, 021422L, 031233L, 043044L,
287 053655L, 062466L, 072277L, 0106110L, 0116701L, 0127532L, 0137323L, 0145154L,
288 0155745L, 0164576L, 0174367L
289 };
290
291 #ifdef CK_TIMERS
292 /*
293 Round-trip timer calculations adapted from Tim Kientzle's article,
294 "Improving Kermit Performance", Dr Dobb's Journal, February 1996.
295 */
296
297
298 /* R T T I N I T -- Initialize timers at start of transaction */
299
300 VOID
rttinit()301 rttinit() { /* Initialize round-trip timing */
302 int i;
303
304 if (timint == 0)
305 return;
306
307 rttsamples = 0L; /* Samples (packets) */
308 rttvariance = 0L; /* Variance in delay */
309 rttdelay = (long) timint * RTT_SCALE; /* Delay */
310 pktintvl = (long) timint * RTT_SCALE; /* Delay */
311 rttstddev = (long) timint * RTT_SCALE; /* Standard deviation of delay */
312
313 /* Tables of timestamps indexed by packet sequence number */
314
315 for (i = 0; i < 64; i++) {
316 rrttbl[i] = -1; /* Time each packet was received */
317 srttbl[i] = -1; /* Time each packet was sent */
318 }
319 rcvtimo = timint; /* Initial timeout is what user said */
320 }
321
322 /* G E T R T T -- Get packet round trip time */
323 /*
324 Call with nakstate == 0 if file sender, nonzero if receiver,
325 and n == packet sequence number of the packet we just received.
326
327 Returns:
328 -1 on failure with rcvtimo set to timint (what the user said), or:
329 0 on success with rcvtimo set to dynamically calculated value:
330 1 <= rcvtimo <= timint * 3.
331 */
332 int
getrtt(nakstate,n)333 getrtt(nakstate, n) int nakstate, n; {
334 extern int mintime, maxtime;
335 static int prevz = 0, prevr = 0;
336 int x, y, yy, z = 0, zz = 0; /* How long did it take to get here? */
337
338 rcvtimo = timint; /* Default timeout is what user said */
339
340 if (timint == 0) /* We're not timing out. */
341 return(0);
342
343 if (!rttflg) /* Not supposed to be doing this? */
344 return(-1); /* So don't */
345
346 if (!RTT_SCALE) /* Paranoia... */
347 return(-1);
348
349 /* rtimer() (reset timer) is not called until 1st data packet */
350 #ifdef GFTIMER
351 /* rftimer(); */
352 #endif /* GFTIMER */
353 /* S (F [ A ] D* Z)* B */
354
355 /* NOTE: we calculate both the round-trip time AND the packet */
356 /* arrival rate. We don't use the RTT for anything, we just display it. */
357 /* Timeouts are based on the packet arrival rate. */
358
359 if (spackets > 3) { /* Don't start till 4th packet */
360 if (nakstate) { /* File receiver */
361 x = rrttbl[n]; /* Time when I got packet n */
362 y = rrttbl[n > 0 ? n - 1 : 63]; /* Time when I got packet n-1 */
363 yy = srttbl[n > 0 ? n - 1 : 63]; /* Time when I sent ACK(n-1) */
364 if (x > -1 && y > -1) { /* Be careful */
365 z = x - y; /* Packet rate */
366 zz = x - yy; /* Round trip time */
367 z++; /* So sender & receiver differ */
368 debug(F101,"RTT RECV","",z);
369 } else { /* This shouldn't happen */
370 debug(F101,"RTT RECV ERROR spackets","",spackets);
371 debug(F101,"RTT RECV ERROR sequence","",n);
372 return(-1);
373 }
374 } else { /* File sender */
375 x = rrttbl[n]; /* Time when I got ACK(n) */
376 y = rrttbl[n > 0 ? n - 1 : 63]; /* Time when I got packet n-1 */
377 yy = srttbl[n]; /* Time when I sent n */
378 if (x > -1 && y > -1) {
379 z = x - y; /* Packet rate */
380 zz = x - yy; /* Round trip time */
381 debug(F101,"RTT SEND","",z);
382 } else {
383 debug(F100,"RTT SEND ERROR","",0);
384 return(-1);
385 }
386 }
387 if (z < 1) /* For fast connections */
388 z = RTT_SCALE / 2; /* Convert to scale... */
389 else
390 z *= RTT_SCALE;
391 debug(F101,"RTT z scaled","",z);
392
393 if (zz < 1) /* For fast connections */
394 zz = RTT_SCALE / 2; /* Convert to scale... */
395 else
396 zz *= RTT_SCALE;
397
398 rttdelay = zz; /* Round trip time of this packet */
399 #ifdef COMMENT
400 /*
401 This was used in C-Kermit 7.0 (and 6.0?) but not only is it overkill,
402 it also can produce ridiculously long timeouts under certain conditions.
403 Replaced in 8.0 by a far simpler and more aggressive strategy.
404 */
405 if (rttsamples++ == 0L) { /* First sample */
406 pktintvl = z;
407 } else { /* Subsequent samples */
408 long oldavg = pktintvl;
409 long rttdiffsq;
410
411 if (rttsamples > 30) /* Use real average for first 30 */
412 rttsamples = 30; /* then decaying average. */
413
414 /* Average delay, difference squared, variance, std deviation */
415
416 pktintvl += (z - pktintvl) / rttsamples;
417 rttdiffsq = (z - oldavg) * (z - oldavg);
418 rttvariance += (rttdiffsq - rttvariance) / rttsamples;
419 debug(F101,"RTT stddev1","",rttstddev);
420 if (rttstddev < 1L) /* It can be zero, in which case */
421 rttstddev = RTT_SCALE / 3; /* set it to something small... */
422 rttstddev = (rttstddev + rttvariance / rttstddev) / 2;
423 }
424 debug(F101,"RTT stddev2","",rttstddev);
425 debug(F101,"RTT delay ","",pktintvl);
426 rcvtimo = (pktintvl + (3L * rttstddev)) / RTT_SCALE + 1;
427 if (rpackets < 32) /* Allow for slow start */
428 rcvtimo += rcvtimo + 2;
429 else if (rpackets < 64)
430 rcvtimo += rcvtimo / 2 + 1;
431 /* On a reliable link, don't try too hard to time out. */
432 /* Especially on fast local network connections. */
433 if (server && what == W_NOTHING) /* Server command wait */
434 rcvtimo = rcvtimo; /* == srvtim */
435 else if (reliable == SET_ON && rcvtimo > 0) /* Reliable */
436 rcvtimo = rcvtimo +15; /* and not server command wait */
437 else /* Not reliable or server cmd wait */
438 rcvtimo = rcvtimo;
439 if (rcvtimo < mintime) /* Lower bound */
440 rcvtimo = mintime;
441 if (maxtime > 0) { /* User specified an upper bound */
442 if (rcvtimo > maxtime)
443 rcvtimo = maxtime;
444 } else if (maxtime == 0) { /* User didn't specify */
445 if (rcvtimo > timint * 6)
446 rcvtimo = timint * 6;
447 }
448 #else /* COMMENT */
449 #ifdef CKFLOAT
450 {
451 CKFLOAT x;
452 x = (CKFLOAT)(prevz + z + z) / 3.0;
453 rcvtimo = (int)((((CKFLOAT)x * 2.66) / RTT_SCALE) + 0.5);
454 debug(F101,"RTT rcvtimo (float)","",rcvtimo);
455 }
456 #else
457 rcvtimo = (prevz + z + z) / RTT_SCALE;
458 debug(F101,"RTT rcvtimo (int)","",rcvtimo);
459 #endif /* CKFLOAT */
460 #endif /* COMMENT */
461
462 zz = (rttdelay + 500) / 1000;
463 if (rcvtimo > (zz * 3))
464 rcvtimo = zz * 3;
465
466 if (rcvtimo < 1)
467 rcvtimo = 1;
468 if (mintime > 0) {
469 if (rcvtimo < mintime) /* Lower bound */
470 rcvtimo = mintime;
471 }
472 if (maxtime > 0) { /* Upper bound */
473 if (rcvtimo > maxtime)
474 rcvtimo = maxtime;
475 }
476 if (rcvtimo == (prevr - 1))
477 rcvtimo++;
478
479 debug(F101,"RTT final rcvtimo","",rcvtimo);
480 }
481 prevz = z;
482 prevr = rcvtimo;
483 return(0);
484 }
485 #endif /* CK_TIMERS */
486
487 /* I N P U T -- Attempt to read packet number 'pktnum'. */
488
489 /*
490 This is the function that feeds input to Kermit's finite state machine,
491 in the form of a character in the range 32-126, normally a packet type
492 (uppercase letter) or pseudo-packet-type (lowercase letter).
493
494 If a special start state is in effect, that state is returned as if it were
495 the type of an incoming packet.
496 */
497 int
input()498 input() {
499 int type = 0, acktype; /* Received packet type */
500 int x, y, k; /* Workers */
501 int z, pi, nf; /* Worker, packet index, NAK flag */
502 int nak2ack = 0;
503
504 debug(F000,"input sstate","",sstate);
505 debug(F101,"input nakstate","",nakstate);
506 debug(F000,"input sndtyp","",sndtyp);
507 debug(F101,"input xitsta","",xitsta);
508 debug(F101,"input what","",what);
509
510 while (1) { /* Big loop... */
511 /*
512 It is ttchk()'s responsibility to tell us if the connection is broken,
513 and to do so instantly and nondestructively -- no blocking, etc, that would
514 slow down file transfer.
515 */
516 if (ttchk() < 0) {
517 debug(F100,"input CONNECTION BROKEN","",0);
518 fatalio = 1;
519 return('q');
520 }
521 if (sstate != 0) { /* If a start state is in effect, */
522 type = sstate; /* return it like a packet type, */
523 sstate = 0; /* and then nullify it. */
524 numerrs = 0; /* (PWP) no errors so far */
525 return(type);
526 }
527 if (nakstate) { /* This section for file receiver. */
528 if (wslots > 1) { /* If we're doing windows, */
529 x = rseqtbl[winlo]; /* see if desired packet already in. */
530 debug(F101,"input winlo","",winlo);
531 debug(F101,"input rseqtbl[winlo]","",rseqtbl[winlo]);
532 if (x > -1) { /* Already there? */
533 if (r_pkt[x].pk_seq == winlo) { /* (double check) */
534 rsn = winlo; /* Yes, return its info */
535 debug(F101,"input return pre-stashed packet","",rsn);
536 dumprbuf();
537 rdatap = r_pkt[x].pk_adr; /* like rpack would do. */
538 rln = (int)strlen((char *) rdatap);
539 type = r_pkt[x].pk_typ;
540 break;
541 }
542 }
543 }
544 type = rpack(); /* Try to read a packet. */
545 debug(F101,"input rpack","",type);
546
547 while (type == 'e') { /* Handle echoes */
548 debug(F101,"input echo discarded","",type);
549 type = rpack();
550 }
551 #ifdef DEBUG
552 if (deblog) {
553 if (type == 'D')
554 debug(F011,"input type D=",(char *)rdatap,39);
555 else
556 debug(F000,"input type",(char *)rdatap,type);
557 }
558 #endif /* DEBUG */
559 #ifndef OLDCHKINT
560 if (type == 'z') {
561 epktrcvd = 1;
562 errpkt((CHAR *)"User cancelled.");
563 type = 'E';
564 break;
565 }
566 #endif /* OLDCHKINT */
567 if (type < -1) {
568 char * s;
569 s = (type == -2) ?
570 "FAILED - Interrupted" :
571 "FAILED - Connection lost";
572
573 xxscreen(SCR_PT,'q',0L,s);
574 dologend();
575 return('q'); /* Ctrl-C or connection lost */
576 }
577 if (type < 0) { /* Receive window full */
578 /* Another thing to do here would be to delete */
579 /* the highest packet and NAK winlo. But that */
580 /* shouldn't be necessary since the other Kermit */
581 /* should not have sent a packet outside the window. */
582 #ifdef COMMENT
583 char foo[256];
584 ckmakxmsg(foo,256,"Receive window full (rpack): wslots=",
585 ckitoa(wslots)," winlo=",ckitoa(winlo)," pktnum=",
586 ckitoa(pktnum), NULL,NULL,NULL,NULL,NULL,NULL);
587 errpkt((CHAR *)foo);
588 debug(F100,foo,"",0);
589 #else
590 errpkt((CHAR *)"Receive window full");
591 debug(F101,"rpack receive window full","",0);
592 debug(F101," wslots","",wslots);
593 debug(F101," winlo","",winlo);
594 debug(F101," pktnum","",pktnum);
595 #endif
596 dumprbuf();
597 type = 'E';
598 break;
599 }
600 dumprbuf();
601
602 #ifdef OLDCHKINT
603 if (chkint() < 0) { /* Check for console interrupts. */
604 errpkt((CHAR *)"User cancelled."); /* (old way) */
605 type = 'E';
606 break;
607 }
608 #endif /* OLDCHKINT */
609
610 #ifdef STREAMING
611 if (streaming) { /* Streaming */
612 if (type == 'Q' || type == 'T') { /* Errors are fatal. */
613 crunched++; /* For statistics */
614 errpkt((CHAR *)"Transmission error on reliable link.");
615 type = 'E';
616 }
617 }
618 #endif /* STREAMING */
619 if (type == 'E') {
620 debug(F101,"input got E, nakstate","",nakstate);
621 break; /* Error packet */
622 }
623 if (type == 'Q') { /* Crunched packet. */
624 crunched++;
625 numerrs++;
626 /*
627 Packet arrived damaged. It was most likely the packet we were expecting
628 next, so we send a NAK for that packet. Prior to 5A(189), we always
629 NAK'd winlo here, but that was bad because if two (or more) different
630 packets were damaged, we would keep NAKing the first one and never NAK the
631 other ones, which could result in a lengthy series of timeouts. Now we
632 NAK the oldest as-yet-unNAK'd missing packet.
633 */
634 #ifdef CK_TIMERS
635 rcvtimo++; /* Stretch the timeout a little */
636 #endif /* CK_TIMERS */
637 z = (winlo + wslots) % 64; /* Search from winlo to z */
638 debug(F101,"ZZZ crunched z","",z);
639 nf = 0; /* NAK flag not set yet */
640 for (x = winlo; x != z; x = (x + 1) % 64) {
641 debug(F101,"ZZZ x","",x);
642 if (rseqtbl[x] > -1) /* Have I received packet x? */
643 continue; /* Yes, go on. */
644 debug(F101,"ZZZ x not recd yet","",x);
645 pi = sseqtbl[x]; /* No, have I NAK'd it yet? */
646 if (pi < 0 || s_pkt[pi].pk_rtr == 0) {
647 debug(F101,"ZZZ x not NAK'd yet","",x);
648 nack(x); /* No, NAK it now. */
649 nf = 1; /* Flag that I did. */
650 break;
651 }
652 }
653 if (!nf) { /* If we didn't NAK anything above, */
654 debug(F101,"ZZZ NAKing winlo","",winlo);
655 if (nack(winlo) < 0) { /* we have to NAK winlo (again) */
656 errpkt((CHAR *)"Too many retries."); /* Too many */
657 type = 'E';
658 break;
659 }
660 }
661 continue;
662 }
663
664 if (type == 'T') { /* Timeout */
665 #ifndef OS2
666 /* K95 does this its own way */
667 if (server && srvidl) {
668 idletmo = 1;
669 debug(F101,"SERVER IDLE TIMEOUT","",srvidl);
670 return('q');
671 }
672 #endif /* OS2 */
673 #ifdef CK_TIMERS
674 rcvtimo++; /* Stretch the timeout a little */
675 #endif /* CK_TIMERS */
676 timeouts++;
677 debug(F101,"input receive-state timeout, winlo","",winlo);
678 /* NAK only the packet at window-low */
679 debug(F101,"input sending NAK for winlo","",winlo);
680 x = ttchk();
681 if (x > 0) /* Don't give up if there is still */
682 continue; /* something to read. */
683 else if (x < 0) {
684 dologend();
685 fatalio = 1;
686 return('q'); /* Connection Lost */
687 }
688 if (nack(winlo) < 0) {
689 debug(F101,"input sent too many naks","",winlo);
690 errpkt((CHAR *)"Too many retries.");
691 type = 'E';
692 break;
693 } else continue;
694 }
695 if (rsn == winlo) { /* Got the packet we want, done. */
696 #ifdef CK_TIMERS
697 if (rttflg && timint) /* Dynamic round trip timers? */
698 getrtt(nakstate, rsn); /* yes, do it. */
699 else /* JHD 20100208 */
700 rcvtimo = timint; /* JHD 20100208 */
701 #endif /* CK_TIMERS */
702 debug(F101,"input rsn=winlo","",rsn);
703 break;
704 }
705
706 /* Got a packet out of order. */
707
708 debug(F101,"input out of sequence, rsn","",rsn);
709 k = rseqtbl[rsn]; /* Get window slot of this packet. */
710 debug(F101,"input rseqtbl[rsn]","",k);
711 if (k < 0) {
712 debug(F101,"input recv can't find index for rcvd pkt","",rsn);
713 /* Was "Internal error 21" */
714 /* This should not happen */
715 errpkt((CHAR *)"Sliding windows protocol error.");
716 type = 'E';
717 break;
718 }
719 y = chkwin(rsn,winlo,wslots); /* See what window it's in. */
720 debug(F101,"input recv chkwin","",y);
721 if (y == 1) { /* From previous window. */
722 #ifdef STREAMING
723 if (!streaming) /* NO RESEND IF STREAMING! */
724 #endif /* STREAMING */
725 resend(rsn); /* Resend the ACK (might have data) */
726 freerpkt(rsn); /* Get rid of received packet */
727 continue; /* Back to wait for another packet */
728 } else { /* In this window or out of range */
729 if (y < 0) /* If out of range entirely, */
730 freerpkt(rsn); /* release its buffer */
731
732 #ifdef STREAMING
733 if (streaming) { /* Streaming (this shouldn't happen) */
734 errpkt((CHAR *)"Sequence error on reliable link.");
735 type = 'E';
736 break;
737 }
738 #endif /* STREAMING */
739
740 /* If our receive window is full, NAK window-low */
741
742 if (rbufnum < 1) { /* Receive window full? */
743 if (nack(winlo) < 0) { /* No choice, must NAK winlo. */
744 errpkt((CHAR *)"Too many retries."); /* Too many */
745 type = 'E';
746 break;
747 } else continue;
748 }
749 /*
750 Receive window not full. This is a packet in the current window but it is
751 not the desired packet at winlo. So therefore there are gaps before this
752 packet. So we find the "lowest" unNAK'd missing packet, if any, between
753 winlo and this one, and NAK it. If there are no as-yet-unNAK'd missing
754 packets in the window, then we send nothing and go wait for another packet.
755 In theory, this could result in a timeout, but in practice it is likely that
756 the already-NAK'd missing packets are already on their way. Note, we do not
757 NAK ahead of ourselves, as that only creates unnecessary retransmissions.
758 */
759 for (x = winlo; x != rsn; x = (x + 1) % 64) {
760 if (rseqtbl[x] > -1) /* Have I received packet x? */
761 continue; /* Yes, check next sequence number. */
762 pi = sseqtbl[x]; /* No, have I NAK'd it yet? */
763 if (pi < 0 || s_pkt[pi].pk_rtr == 0) {
764 nack(x); /* No, NAK it now. */
765 break;
766 }
767 }
768 }
769 /*!!!*/
770 } else { /* Otherwise file sender... */
771
772 #ifdef STREAMING
773 if (streaming && sndtyp == 'D') {
774 debug(F101,"STREAMING input streaming","",streaming);
775 debug(F000,"STREAMING input sndtyp","",sndtyp);
776 rsn = winlo;
777 type = 'Y'; /* Pretend we got an ACK */
778 }
779 #endif /* STREAMING */
780 if (!nak2ack) { /* NAK(n+1) = ACK(n) */
781 if (wslots > 1) { /* Packet at winlo already ACK'd? */
782 if (sacktbl[winlo]) { /* If so, */
783 sacktbl[winlo] = 0; /* Turn off the ACK'd flag */
784 winlo = (winlo + 1) % 64; /* Rotate the window */
785 type = 'Y'; /* And return ACK */
786 debug(F101,
787 "input send returning pre-stashed ACK","",
788 winlo-1);
789 break;
790 }
791 }
792 #ifdef STREAMING
793 if (!(streaming && sndtyp == 'D')) { /* Not streaming | data */
794 type = rpack(); /* Try to read an acknowledgement */
795 } else { /* Streaming and in Data phase */
796 type = 'Y'; /* Assume all is normal */
797 if (chkint() < 0) /* Check for console interrupts. */
798 type = 'z';
799 else if (ttchk() > 4 + bctu) /* Check for return traffic */
800 type = rpack();
801 debug(F000,"input streaming type","",type);
802 }
803 #endif /* STREAMING */
804 debug(F111,"input send",(char *) rdatap,(int) type);
805 while (type == 'e') { /* Handle echoes */
806 debug(F000,"echo discarded","",type);
807 type = rpack();
808 }
809 #ifndef OLDCHKINT
810 if (type == 'z') {
811 epktrcvd = 1;
812 errpkt((CHAR *)"User cancelled.");
813 type = 'E';
814 break;
815 }
816 #endif /* OLDCHKINT */
817 if (type < -1) {
818 xxscreen(SCR_PT,'q',0L,
819 ((char *)((type == -2) ?
820 "Interrupted" :
821 "Connection lost"))
822 );
823 if (type != -2)
824 dologend();
825 return('q'); /* Ctrl-C or connection lost */
826 }
827 if (type == -1) {
828 #ifdef COMMENT
829 char foo[256];
830 ckmakxmsg(foo,256,
831 "Receive window full (error 18): wslots=",
832 ckitoa(wslots),
833 " winlo=",ckitoa(winlo)," pktnum=",
834 ckitoa(pktnum), NULL,NULL,NULL,NULL,NULL,NULL);
835 errpkt((CHAR *)foo);
836 debug(F100,foo,"",0);
837 #else
838 errpkt((CHAR *)"Receive window full"); /* was "internal */
839 debug(F101," wslots","",wslots); /* error 18" */
840 debug(F101," winlo","",winlo);
841 debug(F101," pktnum","",pktnum);
842 #endif /* COMMENT */
843 dumprbuf();
844 type = 'E';
845 break;
846 }
847 dumprbuf(); /* Debugging */
848
849 #ifdef OLDCHKINT
850 if (chkint() < 0) { /* Check for console interrupts. */
851 errpkt((CHAR *)"User cancelled.");
852 return(type = 'E');
853 }
854 #endif /* OLDCHKINT */
855
856 /* Got a packet */
857
858 #ifdef STREAMING
859 if (streaming) { /* Streaming */
860 if (type == 'Q' || type == 'T') { /* Errors are fatal. */
861 crunched++; /* For statistics */
862 errpkt((CHAR *)"Transmission error on reliable link.");
863 type = 'E';
864 }
865 }
866 #endif /* STREAMING */
867 if (type == 'E') {
868 debug(F101,"input send got E, nakstate","",nakstate);
869 break; /* Error packet */
870 }
871 if (type == 'Q') { /* Crunched packet */
872 crunched++; /* For statistics */
873 numerrs++; /* For packet resizing */
874 x = resend(winlo); /* Resend window-low */
875 if (x < 0) {
876 type = 'E';
877 errpkt((CHAR *)"Too many retries");
878 break;
879 }
880 continue;
881 }
882 if (type == 'T') { /* Timeout waiting for ACKs. */
883 timeouts++; /* Count it */
884 numerrs++; /* Count an error too */
885 debug(F101,"input send state timeout, winlo","",winlo);
886
887 /* Retransmit the oldest un-ACK'd packet. */
888
889 debug(F101,"input send resending winlo","",winlo);
890 if (resend(winlo) < 0) { /* Check retries */
891 debug(F101,"input send too many resends","",maxtry);
892 errpkt((CHAR *)"Too many retries");
893 return(type = 'E');
894 }
895 #ifdef NEWDPL
896 /* Reduce prevailing packet length */
897 x = sseqtbl[winlo]; /* Get length of packet we want ACKd */
898 if (x > -1) { /* Only if we have a valid index */
899 if (s_pkt[x].pk_typ == 'D') { /* only for D packets */
900 spsiz = (s_pkt[x].pk_len + 8) >> 1; /* halve it */
901 if (spsiz < 20) spsiz = 20; /* within reason */
902 debug(F101,"input T cut packet length","",spsiz);
903 }
904 }
905 #endif /* NEWDPL */
906 continue;
907 }
908 }
909 /* Got an actual normal packet */
910
911 nak2ack = 0; /* Unset this flag. */
912 y = chkwin(rsn,winlo,wslots); /* Is it in the window? */
913 debug(F101,"input send rsn","",rsn);
914 debug(F101,"input send winlo","",winlo);
915 debug(F101,"input send chkwin","",y);
916
917 if (type == 'Y') { /* Got an ACK */
918 if (y == 0) { /* In current window */
919 if (spackets < 4) /* Error counter doesn't count */
920 numerrs = 0; /* until data phase. */
921 sacktbl[rsn]++; /* Mark the packet as ACK'd */
922 x = sseqtbl[rsn]; /* Get ACK'd packet's buffer index */
923 debug(F101,"bestlen ack x","",x);
924 #ifdef NEWDPL
925 if (x > -1) {
926 acktype = s_pkt[x].pk_typ; /* Get type */
927 debug(F000,"bestlen ack type","",acktype);
928
929 if (acktype == 'D') { /* Adjust data packet length */
930 if (spsiz > bestlen) {
931 bestlen = spsiz;
932 debug(F101,"bestlen B","",bestlen);
933 }
934 #ifdef DEBUG
935 if (deblog) {
936 debug(F101,"bestlen retry","",s_pkt[x].pk_rtr);
937 debug(F101,"bestlen len","",s_pkt[x].pk_len);
938 debug(F101,"bestlen spackets","",spackets);
939 }
940 #endif /* DEBUG */
941 /* Set new best length */
942 if (s_pkt[x].pk_rtr == 0 &&
943 s_pkt[x].pk_len + 8 > bestlen) {
944 bestlen = s_pkt[x].pk_len + 8;
945 if (bestlen > spmax)
946 bestlen = spmax;
947 debug(F101,"bestlen A","",bestlen);
948 }
949 #ifdef DEBUG
950 if (deblog) {
951 debug(F101,"bestlen wslots","",wslots);
952 debug(F101,"bestlen maxsend","",maxsend);
953 }
954 #endif /* DEBUG */
955 /* Slow start */
956 if (slostart &&
957 (maxsend <= spmax) &&
958 (rpackets < 11) &&
959 (numerrs == 0)) {
960 spsiz = spsiz << 1;
961 debug(F101,"bestlen spsiz A","",spsiz);
962
963 /* Creep up to best length */
964 } else if ((spackets > 5) &&
965 (spsiz < bestlen - 8)) {
966 spsiz += (bestlen - spsiz) / 3;
967 debug(F101,"bestlen spsiz B","",spsiz);
968
969 /* Push the envelope */
970 } else if ((spackets % (wslots + 1) == 0) &&
971 (spackets > 6) &&
972 (bestlen < spmax - 8) &&
973 (spsiz < spmax)) {
974 spsiz += (spmax - bestlen) / 3;
975 debug(F101,"bestlen spsiz C","",spsiz);
976 }
977 /* But not too far */
978 if (spsiz > spmax) {
979 spsiz = spmax;
980 debug(F101,"bestlen spsiz D","",spsiz);
981 }
982 }
983 }
984 #endif /* NEWDPL */
985
986 #ifdef CK_TIMERS
987 if (rttflg && timint) /* If doing dynamic timers */
988 getrtt(nakstate, rsn); /* call routine to set it. */
989 else /* JHD 20100208 */
990 rcvtimo = timint; /* JHD 20100208 */
991 #endif /* CK_TIMERS */
992 /*
993 NOTE: The following statement frees the buffer of the ACK we just got.
994 But the upper layers still need the data, like if it's the ACK to an I,
995 S, F, D, Z, or just about any kind of packet. So for now, freerbuf()
996 deallocates the buffer, but does not erase the data or destroy the pointer
997 to it. There's no other single place where these receive buffers can be
998 correctly freed (?) ...
999 */
1000 freerpkt(rsn); /* Free the ACK's buffer */
1001 freesbuf(rsn); /* *** Free the sent packet's buffer */
1002 if (rsn == winlo) { /* Got the one we want */
1003 sacktbl[winlo] = 0;
1004 winlo = (winlo + 1) % 64;
1005 debug(F101,"input send rotated send window","",winlo);
1006 break; /* Return the ACK */
1007 } else {
1008 debug(F101,"input send mark pkt","",rsn);
1009 continue; /* Otherwise go read another packet */
1010 }
1011 } else if (y == 1 && wslots < 2) { /* (190) ACK for previous */
1012 numerrs++; /* == NAK for current, count error */
1013 debug(F101,"input send ACK for previous","",rsn);
1014 freerpkt(rsn); /* Free NAK's buffer */
1015 x = resend(winlo); /* Resend current packet */
1016 if (x < 0) {
1017 type = 'E';
1018 errpkt((CHAR *)"Too many retries");
1019 break;
1020 } else continue; /* Resend ok, go read another packet */
1021 } else { /* Other cases, just ignore */
1022 debug(F101,"input send ACK out of window","",rsn);
1023 freerpkt(rsn);
1024 continue;
1025 }
1026 }
1027 if (type == 'N') { /* NAK */
1028 numerrs++; /* Count an error */
1029 #ifdef STREAMING
1030 if (streaming) { /* Streaming */
1031 errpkt((CHAR *)"NAK received on reliable link.");
1032 type = 'E';
1033 break;
1034 }
1035 #endif /* STREAMING */
1036
1037 debug(F101,"input send NAK","",rsn);
1038 #ifdef NEWDPL
1039 /* Reduce prevailing packet length */
1040 x = sseqtbl[rsn]; /* Length of packet that was NAK'd */
1041 if (x > -1) { /* If it's a Data packet we've sent */
1042 if (s_pkt[x].pk_typ == 'D') {
1043 spsiz = (s_pkt[x].pk_len + 8) >> 1; /* Halve length */
1044 #ifdef COMMENT
1045 /* This might be a good idea -- haven't tried it ... */
1046 if (bestlen > 0 && spsiz > bestlen)
1047 spsiz = bestlen;
1048 #endif /* COMMENT */
1049 if (spsiz < 20) spsiz = 20;
1050 debug(F101,"input N cut packet length","",spsiz);
1051 }
1052 }
1053 #endif /* NEWDPL */
1054 freerpkt(rsn); /* Free buffer where NAK lies. */
1055 if (y == 0) { /* In current window */
1056 debug(F100," in window","",0);
1057 k = sseqtbl[rsn]; /* Get pointer to NAK'd packet. */
1058 if (k < 0 || (k > -1 && s_pkt[k].pk_typ == ' ')) {
1059 x = resend(winlo); /* Packet we haven't sent yet. */
1060 } else {
1061 x = resend(rsn); /* Resend requested packet. */
1062 }
1063 if (x < 0) { /* Resend error is fatal. */
1064 type = 'E';
1065 errpkt((CHAR *)"Too many retries");
1066 break;
1067 } else continue; /* Resend ok, go read another packet */
1068 } else if ((rsn == (pktnum + 1) % 64)) { /* NAK for next pkt */
1069 if (wslots > 1) {
1070 debug( F101,"NAK for next packet, windowing","",rsn);
1071 x = resend(winlo); /* Resend window-low */
1072 if (x < 0) {
1073 type = 'E';
1074 errpkt((CHAR *)"Too many retries");
1075 break;
1076 }
1077 continue; /* Go back and read another pkt */
1078 }
1079 debug(F101,"NAK for next packet, no windowing","",rsn);
1080 x = (rsn == 0) ? 63 : rsn - 1;
1081 if (x == 0 && (sndtyp == 'S' || sndtyp == 'I')) {
1082 resend(0); /* ACK for S or I packet missing */
1083 continue; /* so resend the S or I */
1084 }
1085 rsn = x; /* Else, treat NAK(n+1) as ACK(n) */
1086 nak2ack = 1; /* Go back and process the ACK */
1087 continue;
1088 } else if (y > 0) { /* NAK for pkt we can't resend */
1089 debug(F101," NAK out of window","",rsn); /* bad... */
1090 type = 'E';
1091 errpkt((CHAR *)"NAK out of window");
1092 break;
1093 } else continue; /* Ignore other NAKs */
1094 } /* End of file-sender NAK handler */
1095
1096 if (rsn == winlo) { /* Not ACK, NAK, timeout, etc. */
1097 debug(F000,"input send unexpected type","",type);
1098 break;
1099 }
1100 } /* End of file-sender section */
1101 } /* End of input() while() loop */
1102 /*
1103 When the window size is 1 and we have the packet we want, there can not
1104 possibly be anything waiting for us on the connection that is useful to us.
1105 However, there might be redundant copies of a packet we already got, which
1106 would cause needless cycles of repeated packets. Therefore we flush the
1107 communications input buffer now to try to get rid of undesired and unneeded
1108 packets that we have not read yet.
1109
1110 Actually, the first sentence above is not entirely true: there could be an
1111 Error packet waiting to be read. Flushing an E packet is bad because it
1112 will not be resent, and we'll go into a cycle of timing out and
1113 retransmitting up to the retry limit. - fdc 2007/03/02
1114 */
1115 if (wslotn == 1 /* (not wslots!) */
1116 #ifdef STREAMING
1117 && !streaming /* But not when streaming */
1118 #endif /* STREAMING */
1119 ) {
1120 debug(F100,"input about to flush","",0);
1121 ttflui(); /* Got what we want, clear input buffer. */
1122 }
1123 #ifndef NEWDPL
1124 if (!nakstate) /* When sending */
1125 rcalcpsz(); /* recalculate size every packet */
1126 #endif /* NEWDPL */
1127 if (type == 'E')
1128 xitsta |= (what ? what : 1); /* Remember what failed. */
1129 debug(F101,"input winlo","",winlo);
1130 debug(F101,"input rsn","",rsn);
1131 debug(F000,"input returning type","",type);
1132 return(rcvtyp = type); /* Success, return packet type. */
1133 }
1134
1135 #ifdef PARSENSE
1136 /* P A R C H K -- Check if Kermit packet has parity */
1137
1138 /*
1139 Call with s = pointer to packet, start = packet start character, n = length.
1140 Returns 0 if packet has no parity, -1 on error, or, if packet has parity:
1141 'e' for even, 'o' for odd, 'm' for mark. Space parity cannot be sensed.
1142 So a return value of 0 really means either space or none.
1143 Returns -2 if parity has already been checked during this protocol operation.
1144 */
1145 int
1146 #ifdef CK_ANSIC
parchk(CHAR * s,CHAR start,int n)1147 parchk(CHAR *s, CHAR start, int n)
1148 #else
1149 parchk(s,start,n) CHAR *s, start; int n;
1150 #endif /* CK_ANSIC */
1151 /* parchk */ {
1152 CHAR s0, s1, s2, s3;
1153
1154 debug(F101,"parchk n","",n);
1155 debug(F101,"parchk start","",start);
1156
1157 s0 = s[0] & 0x7f; /* Mark field (usually Ctrl-A) */
1158
1159 if (s0 != start || n < 5) return(-1); /* Not a valid packet */
1160
1161 /* Look at packet control fields, which never have 8th bit set */
1162 /* First check for no parity, most common case. */
1163
1164 if (((s[0] | s[1] | s[2] | s[3]) & 0x80) == 0)
1165 return(0); /* No parity or space parity */
1166
1167 /* Check for mark parity */
1168
1169 if (((s[0] & s[1] & s[2] & s[3]) & 0x80) == 0x80)
1170 return('m'); /* Mark parity */
1171
1172 /* Packet has some kind of parity */
1173 /* Make 7-bit copies of control fields */
1174
1175 s1 = s[1] & 0x7f; /* LEN */
1176 s2 = s[2] & 0x7f; /* SEQ */
1177 s3 = s[3] & 0x7f; /* TYPE */
1178
1179 /* Check for even parity */
1180
1181 if ((s[0] == p_tbl[s0]) &&
1182 (s[1] == p_tbl[s1]) &&
1183 (s[2] == p_tbl[s2]) &&
1184 (s[3] == p_tbl[s3]))
1185 return('e');
1186
1187 /* Check for odd parity */
1188
1189 if ((s[0] != p_tbl[s0]) &&
1190 (s[1] != p_tbl[s1]) &&
1191 (s[2] != p_tbl[s2]) &&
1192 (s[3] != p_tbl[s3]))
1193 return('o');
1194
1195 /* Otherwise it's probably line noise. Let checksum calculation catch it. */
1196
1197 return(-1);
1198 }
1199 #endif /* PARSENSE */
1200
1201 /*
1202 Check to make sure timeout intervals are long enough to allow maximum
1203 length packets to get through before the timer goes off. If not, the
1204 timeout interval is adjusted upwards.
1205
1206 This routine is called at the beginning of a transaction, before we
1207 know anything about the delay characteristics of the line. It works
1208 only for serial communication devices; it trusts the speed reported by
1209 the operating system.
1210
1211 Call with a timout interval. Returns it, adjusted if necessary.
1212 */
1213 int
chktimo(timo,flag)1214 chktimo(timo,flag) int timo, flag; {
1215 long cps, z; int x, y;
1216 #ifdef STREAMING
1217 debug(F101,"chktimo streaming","",streaming);
1218 if (streaming)
1219 return(0);
1220 #endif /* STREAMING */
1221
1222 debug(F101,"chktimo timo","",timo); /* Timeout before adjustment */
1223 debug(F101,"chktimo flag","",flag);
1224
1225 if (flag) /* Don't change timeout if user */
1226 return(timo); /* gave SET SEND TIMEOUT command. */
1227 debug(F101,"chktimo spmax","",spmax);
1228 debug(F101,"chktimo urpsiz","",urpsiz);
1229
1230 if (!network) { /* On serial connections... */
1231 speed = ttgspd(); /* Get current speed. */
1232 if (speed > 0L) {
1233 cps = speed / 10L; /* Convert to chars per second */
1234 if (cps > 0L) {
1235 long plen; /* Maximum of send and rcv pkt size */
1236 z = cps * (long) timo; /* Chars per timeout interval */
1237 z -= z / 10L; /* Less 10 percent */
1238 plen = spmax;
1239 if (urpsiz > spmax) plen = urpsiz;
1240 debug(F101,"chktimo plen","",plen);
1241 if (z < plen) { /* Compare with packet size */
1242 x = (int) ((long) plen / cps); /* Adjust if necessary */
1243 y = x / 10; /* Add 10 percent for safety */
1244 if (y < 2) y = 2; /* Or 2 seconds, whichever is more */
1245 x += y;
1246 if (x > timo) /* If this is greater than current */
1247 timo = x; /* timeout, change the timeout */
1248 debug(F101,"chktimo new timo","",timo);
1249 }
1250 }
1251 }
1252 }
1253 return(timo);
1254 }
1255
1256 /* S P A C K -- Construct and send a packet */
1257
1258 /*
1259 spack() sends a packet of the given type, sequence number n, with len data
1260 characters pointed to by d, in either a regular or extended- length packet,
1261 depending on len. Returns the number of bytes actually sent, or else -1
1262 upon failure. Uses global npad, padch, mystch, bctu, data. Leaves packet
1263 fully built and null-terminated for later retransmission by resend().
1264 Updates global sndpktl (send-packet length).
1265
1266 NOTE: The global pointer "data" is assumed to point into the 7th position
1267 of a character array (presumably in packet buffer for the current packet).
1268 It was used by getpkt() to build the packet data field. spack() fills in
1269 the header to the left of the data pointer (the data pointer is defined
1270 in getsbuf() in ckcfn3.c). If the address "d" is the same as "data", then
1271 the packet's data field has been built "in place" and need not be copied.
1272 */
1273 int
1274 #ifdef CK_ANSIC
spack(char pkttyp,int n,int len,CHAR * d)1275 spack(char pkttyp, int n, int len, CHAR *d)
1276 #else
1277 spack(pkttyp,n,len,d) char pkttyp; int n, len; CHAR *d;
1278 #endif /* CK_ANSIC */
1279 /* spack */ {
1280 register int i;
1281 int ix, j, k, x, lp, longpkt, copy, loglen;
1282
1283 #ifdef GFTIMER
1284 CKFLOAT t1 = 0.0, t2 = 0.0;
1285 #endif /* GFTIMER */
1286
1287 register CHAR *cp, *mydata;
1288 unsigned crc;
1289
1290 copy = (d != data); /* Flag whether data must be copied */
1291
1292 #ifdef DEBUG
1293 if (deblog) { /* Save lots of function calls! */
1294 debug(F101,"spack n","",n);
1295 #ifdef COMMENT
1296 if (pkttyp != 'D') { /* Data packets would be too long */
1297 debug(F111,"spack data",data,data);
1298 debug(F111,"spack d",d,d);
1299 }
1300 #endif /* COMMENT */
1301 debug(F101,"spack len","",len);
1302 debug(F101,"spack copy","",copy);
1303 }
1304 #endif /* DEBUG */
1305
1306 longpkt = (len + bctl + 2) > 94; /* Decide whether it's a long packet */
1307 mydata = data - 7 + (longpkt ? 0 : 3); /* Starting position of header */
1308 k = sseqtbl[n]; /* Packet structure info for pkt n */
1309 #ifdef COMMENT
1310 #ifdef DEBUG
1311 if (deblog) { /* Save 2 more function calls... */
1312 debug(F101,"spack mydata","",mydata);
1313 debug(F101,"spack sseqtbl[n]","",k);
1314 if (k < 0) {
1315 #ifdef STREAMING
1316 if (!streaming)
1317 #endif /* STREAMING */
1318 debug(F101,"spack sending packet out of window","",n);
1319 }
1320 }
1321 #endif /* DEBUG */
1322 #endif /* COMMENT */
1323 if (k > -1) {
1324 s_pkt[k].pk_adr = mydata; /* Remember address of packet. */
1325 s_pkt[k].pk_seq = n; /* Record sequence number */
1326 s_pkt[k].pk_typ = pkttyp; /* Record packet type */
1327 }
1328 spktl = 0; /* Initialize length of this packet */
1329 i = 0; /* and position in packet. */
1330
1331 /* Now fill the packet */
1332
1333 mydata[i++] = mystch; /* MARK */
1334 lp = i++; /* Position of LEN, fill in later */
1335
1336 mydata[i++] = tochar(n); /* SEQ field */
1337 mydata[i++] = pkttyp; /* TYPE field */
1338 j = len + bctl; /* Length of data + block check */
1339 if (longpkt) { /* Long packet? */
1340 int x; /* Yes, work around SCO Xenix/286 */
1341 #ifdef CKTUNING
1342 unsigned int chk;
1343 #endif /* CKTUNING */
1344 x = j / 95; /* compiler bug... */
1345 mydata[lp] = tochar(0); /* Set LEN to zero */
1346 mydata[i++] = tochar(x); /* Extended length, high byte */
1347 mydata[i++] = tochar(j % 95); /* Extended length, low byte */
1348 #ifdef CKTUNING
1349 /* Header checksum - skip the function calls and loops */
1350 chk = (unsigned) mydata[lp] +
1351 (unsigned) mydata[lp+1] +
1352 (unsigned) mydata[lp+2] +
1353 (unsigned) mydata[lp+3] +
1354 (unsigned) mydata[lp+4] ;
1355 mydata[i++] = tochar((CHAR) ((((chk & 0300) >> 6) + chk) & 077));
1356 #else
1357 mydata[i] = '\0'; /* Terminate for header checksum */
1358 mydata[i++] = tochar(chk1(mydata+lp,5));
1359 #endif /* CKTUNING */
1360 } else mydata[lp] = tochar(j+2); /* Normal LEN */
1361 /*
1362 When sending a file, the data is already in the right place. If it weren't,
1363 it might make sense to optimize this section by using memcpy or bcopy
1364 (neither of which are portable), but only if our packets were rather long.
1365 When receiving, we're only sending ACKs so it doesn't matter. So count the
1366 following loop as a sleeping dog.
1367 */
1368 if (copy) /* Data field built in place? */
1369 for ( ; len--; i++) mydata[i] = *d++; /* No, must copy. */
1370 else /* Otherwise, */
1371 i += len; /* Just skip past data field. */
1372 mydata[i] = '\0'; /* Null-terminate for checksum calc. */
1373
1374 switch (bctu) { /* Block check */
1375 case 1: /* 1 = 6-bit chksum */
1376 ix = i - lp; /* Avoid "order of operation" error */
1377 mydata[i++] = tochar(chk1(mydata+lp,ix));
1378 break;
1379 case 2: /* 2 = 12-bit chksum */
1380 j = chk2(mydata+lp,i-lp);
1381 mydata[i++] = (unsigned)tochar((j >> 6) & 077);
1382 mydata[i++] = (unsigned)tochar(j & 077);
1383 break;
1384 case 3: /* 3 = 16-bit CRC */
1385 crc = chk3(mydata+lp,i-lp);
1386 mydata[i++] = (unsigned)tochar(((crc & 0170000)) >> 12);
1387 mydata[i++] = (unsigned)tochar((crc >> 6) & 077);
1388 mydata[i++] = (unsigned)tochar(crc & 077);
1389 break;
1390 case 4: /* 2 = 12-bit chksum, blank-free */
1391 j = chk2(mydata+lp,i-lp);
1392 mydata[i++] =
1393 (unsigned)(tochar((unsigned)(((j >> 6) & 077) + 1)));
1394 mydata[i++] = (unsigned)(tochar((unsigned)((j & 077) + 1)));
1395 break;
1396 }
1397 loglen = i;
1398 mydata[i++] = seol; /* End of line (packet terminator) */
1399 #ifdef TCPSOCKET
1400 /*
1401 If TELNET connection and packet terminator is carriage return,
1402 we must stuff either LF or NUL, according to SET TELNET NEWLINE-MODE
1403 (tn_nlm), to meet the TELNET NVT specification, unless user said RAW.
1404
1405 If NEWLINE-MODE is set to LF instead of CR, we still send CR-NUL
1406 on a NVT connection and CR on a binary connection.
1407 */
1408 if (
1409 #ifdef STREAMING
1410 !dontsend &&
1411 #endif /* STREAMING */
1412 ((network && ttnproto == NP_TELNET) || (!local && sstelnet))
1413 && seol == CR) {
1414 switch (TELOPT_ME(TELOPT_BINARY) ? tn_b_nlm : tn_nlm) {
1415 case TNL_CR: /* NVT or BINARY */
1416 break;
1417 case TNL_CRNUL:
1418 mydata[i++] = NUL;
1419 break;
1420 case TNL_CRLF:
1421 mydata[i++] = LF;
1422 break;
1423 }
1424 }
1425 #endif /* TCPSOCKET */
1426 mydata[i] = '\0'; /* Terminate string */
1427 if (
1428 #ifdef STREAMING
1429 !dontsend &&
1430 #endif /* STREAMING */
1431 pktlog
1432 ) /* Save a function call! */
1433 logpkt('s',n,mydata,loglen); /* Log the packet */
1434
1435 /* (PWP) add the parity quickly at the end */
1436 if (parity) {
1437 switch (parity) {
1438 case 'e': /* Even */
1439 for (cp = &mydata[i-1]; cp >= mydata; cp--)
1440 *cp = p_tbl[*cp];
1441 break;
1442 case 'm': /* Mark */
1443 for (cp = &mydata[i-1]; cp >= mydata; cp--)
1444 *cp |= 128;
1445 break;
1446 case 'o': /* Odd */
1447 for (cp = &mydata[i-1]; cp >= mydata; cp--)
1448 *cp = p_tbl[*cp] ^ 128;
1449 break;
1450 case 's': /* Space */
1451 for (cp = &mydata[i-1]; cp >= mydata; cp--)
1452 *cp &= 127;
1453 break;
1454 }
1455 }
1456 if (pktpaus) msleep(pktpaus); /* Pause if requested */
1457 x = 0;
1458
1459 if (npad) {
1460 #ifdef STREAMING
1461 if (dontsend)
1462 x = 0;
1463 else
1464 #endif /* STREAMING */
1465 x = ttol(padbuf,npad); /* Send any padding */
1466 }
1467 if (x > -1) {
1468 #ifdef CK_TIMERS
1469 if (timint > 0) {
1470 if (pkttyp == 'N')
1471 srttbl[n > 0 ? n-1 : 63] = gtimer();
1472 else
1473 srttbl[n] = gtimer();
1474 }
1475 #endif /* CK_TIMERS */
1476 spktl = i; /* Remember packet length */
1477 if (k > -1)
1478 s_pkt[k].pk_len = spktl; /* also in packet info structure */
1479
1480 #ifdef DEBUG
1481 #ifdef GFTIMER
1482 /*
1483 This code shows (in the debug log) how long it takes write() to execute.
1484 Sometimes on a congested TCP connection, it can surprise you -- 90 seconds
1485 or more...
1486 */
1487 if (
1488 #ifdef STREAMING
1489 !dontsend &&
1490 #endif /* STREAMING */
1491 deblog
1492 )
1493 t1 = gftimer();
1494 #endif /* GFTIMER */
1495 #endif /* DEBUG */
1496
1497 #ifdef STREAMING
1498 if (dontsend) {
1499 debug(F000,"STREAMING spack skipping","",pkttyp);
1500 x = 0;
1501 } else
1502 #endif /* STREAMING */
1503 x = ttol(mydata,spktl); /* Send the packet */
1504 }
1505 #ifdef STREAMING
1506 if (!dontsend) {
1507 #endif /* STREAMING */
1508 debug(F101,"spack spktl","",spktl);
1509 debug(F101,"spack ttol returns","",x);
1510 if (x < 0) { /* Failed. */
1511 if (local && x < -1) {
1512 xxscreen(SCR_ST,ST_ERR,0L,"FAILED: Connection lost");
1513 /* We can't send an E packet because the connection is lost. */
1514 epktsent = 1; /* So pretend we sent one. */
1515 fatalio = 1; /* Remember we got a fatal i/o error */
1516 dologend();
1517 ckstrncpy((char *)epktmsg,"Connection lost",PKTMSGLEN);
1518 }
1519 return(x);
1520 }
1521 if (spktl > maxsend) /* Keep track of longest packet sent */
1522 maxsend = spktl;
1523 #ifdef DEBUG
1524 #ifdef GFTIMER
1525 if (deblog) { /* Log elapsed time for write() */
1526 t2 = gftimer();
1527 debug(F101,"spack ttol msec","",(long)((t2-t1)*1000.0));
1528 }
1529 #endif /* GFTIMER */
1530 #endif /* DEBUG */
1531 #ifdef STREAMING
1532 }
1533 #endif /* STREAMING */
1534
1535 sndtyp = pkttyp; /* Remember packet type for echos */
1536 #ifdef STREAMING
1537 if (!dontsend) { /* If really sent, */
1538 spackets++; /* count it. */
1539 flco += spktl; /* Count the characters */
1540 tlco += spktl; /* for statistics... */
1541 #ifdef DEBUG
1542 if (deblog) { /* Save two function calls! */
1543 dumpsbuf(); /* Dump send buffers to debug log */
1544 debug(F111,"spack calling screen, mydata=",mydata,n);
1545 }
1546 #endif /* DEBUG */
1547 }
1548 #endif /* STREAMING */
1549 if (local) {
1550 int x = 0;
1551 if (fdispla != XYFD_N) x = 1;
1552 if ((fdispla == XYFD_B) && (pkttyp == 'D' || pkttyp == 'Y')) x = 0;
1553 if (x)
1554 xxscreen(SCR_PT,pkttyp,(long)n,(char *)mydata); /* Update screen */
1555 }
1556 return(spktl); /* Return length */
1557 }
1558
1559 /* C H K 1 -- Compute a type-1 Kermit 6-bit checksum. */
1560
1561 int
chk1(pkt,len)1562 chk1(pkt,len) register CHAR *pkt; register int len; {
1563 register unsigned int chk;
1564 #ifdef CKTUNING
1565 #ifdef COMMENT
1566 register unsigned int m; /* Avoid function call */
1567 m = (parity) ? 0177 : 0377;
1568 for (chk = 0; len-- > 0; pkt++)
1569 chk += *pkt & m;
1570 #else
1571 chk = 0;
1572 while (len-- > 0) chk += (unsigned) *pkt++;
1573 #endif /* COMMENT */
1574 #else
1575 chk = chk2(pkt,len);
1576 #endif /* CKTUNING */
1577 chk = (((chk & 0300) >> 6) + chk) & 077;
1578 debug(F101,"chk1","",chk);
1579 return((int) chk);
1580 }
1581
1582 /* C H K 2 -- Compute the numeric sum of all the bytes in the packet. */
1583
1584 unsigned int
chk2(pkt,len)1585 chk2(pkt,len) register CHAR *pkt; register int len; {
1586 register long chk;
1587 #ifdef COMMENT
1588 register unsigned int m;
1589 m = (parity) ? 0177 : 0377;
1590 for (chk = 0; len-- > 0; pkt++)
1591 chk += *pkt & m;
1592 #else
1593 /* Parity has already been stripped */
1594 chk = 0L;
1595 while (len-- > 0) chk += (unsigned) *pkt++;
1596 #endif /* COMMENT */
1597 debug(F101,"chk2","",(unsigned int) (chk & 07777));
1598 return((unsigned int) (chk & 07777));
1599 }
1600
1601 /* C H K 3 -- Compute a type-3 Kermit block check. */
1602 /*
1603 Calculate the 16-bit CRC-CCITT of a null-terminated string using a lookup
1604 table. Assumes the argument string contains no embedded nulls.
1605 */
1606 #ifdef COMMENT
1607 unsigned int
chk3(pkt,parity,len)1608 chk3(pkt,parity,len) register CHAR *pkt; int parity; register int len; {
1609 register long c, crc;
1610 register unsigned int m;
1611 m = (parity) ? 0177 : 0377;
1612 for (crc = 0; len-- > 0; pkt++) {
1613 c = crc ^ (long)(*pkt & m);
1614 crc = (crc >> 8) ^ (crcta[(c & 0xF0) >> 4] ^ crctb[c & 0x0F]);
1615 }
1616 return((unsigned int) (crc & 0xFFFF));
1617 }
1618 #else
1619 unsigned int
chk3(pkt,len)1620 chk3(pkt,len) register CHAR *pkt; register int len; {
1621 register long c, crc;
1622 for (crc = 0; len-- > 0; pkt++) {
1623 c = crc ^ (long)(*pkt);
1624 crc = (crc >> 8) ^ (crcta[(c & 0xF0) >> 4] ^ crctb[c & 0x0F]);
1625 }
1626 debug(F101,"chk3","",(unsigned int) (crc & 0xFFFF));
1627 return((unsigned int) (crc & 0xFFFF));
1628 }
1629 #endif /* COMMENT */
1630
1631 /* N X T P K T -- Next Packet */
1632 /*
1633 Get packet number of next packet to send and allocate a buffer for it.
1634 Returns:
1635 0 on success, with global pktnum set to the packet number;
1636 -1 on failure to allocate buffer (fatal);
1637 -2 if resulting packet number is outside the current window.
1638 */
1639 int
nxtpkt()1640 nxtpkt() { /* Called by file sender */
1641 int j, n, x;
1642
1643 debug(F101,"nxtpkt pktnum","",pktnum);
1644 debug(F101,"nxtpkt winlo ","",winlo);
1645 n = (pktnum + 1) % 64; /* Increment packet number mod 64 */
1646 debug(F101,"nxtpkt n","",n);
1647 #ifdef STREAMING
1648 if (!streaming) {
1649 x = chkwin(n,winlo,wslots); /* Don't exceed window boundary */
1650 debug(F101,"nxtpkt chkwin","",x);
1651 if (x)
1652 return(-2);
1653 j = getsbuf(n); /* Get a buffer for packet n */
1654 if (j < 0) {
1655 debug(F101,"nxtpkt getsbuf failure","",j);
1656 return(-1);
1657 }
1658 }
1659 #endif /* STREAMING */
1660 pktnum = n;
1661 return(0);
1662 }
1663
1664 /* Functions for sending ACKs and NAKs */
1665
1666 /* Note, we should only ACK the packet at window-low (winlo) */
1667 /* However, if an old packet arrives again (e.g. because the ACK we sent */
1668 /* earlier was lost), we ACK it again. */
1669
1670 int
ack()1671 ack() { /* Acknowledge the current packet. */
1672 return(ackns(winlo,(CHAR *)""));
1673 }
1674
1675 #ifdef STREAMING
1676 int
fastack()1677 fastack() { /* Acknowledge packet n */
1678 int j, k, n, x;
1679 n = winlo;
1680
1681 k = rseqtbl[n]; /* First find received packet n. */
1682 debug(F101,"STREAMING fastack k","",k);
1683 freesbuf(n); /* Free current send-buffer, if any */
1684 if ((j = getsbuf(n)) < 0) {
1685 /* This can happen if we have to re-ACK an old packet that has */
1686 /* already left the window. It does no harm. */
1687 debug(F101,"STREAMING fastack can't getsbuf","",n);
1688 }
1689 dontsend = 1;
1690 x = spack('Y',n,0,(CHAR *)""); /* Now send it (but not really) */
1691 dontsend = 0;
1692 if (x < 0) return(x);
1693 debug(F101,"STREAMING fastack x","",x);
1694 if (k > -1)
1695 freerbuf(k); /* don't need it any more */
1696 if (j > -1)
1697 freesbuf(j); /* and don't need to keep ACK either */
1698 winlo = (winlo + 1) % 64;
1699 return(0);
1700 }
1701 #endif /* STREAMING */
1702
1703 int
ackns(n,s)1704 ackns(n,s) int n; CHAR *s; { /* Acknowledge packet n */
1705 int j, k, x;
1706 debug(F111,"ackns",s,n);
1707
1708 k = rseqtbl[n]; /* First find received packet n. */
1709 debug(F101,"ackns k","",k);
1710 freesbuf(n); /* Free current send-buffer, if any */
1711 if ((j = getsbuf(n)) < 0) {
1712 /* This can happen if we have to re-ACK an old packet that has */
1713 /* already left the window. It does no harm. */
1714 debug(F101,"ackns can't getsbuf","",n);
1715 }
1716 x = spack('Y',n,(int)strlen((char *)s),s); /* Now send it. */
1717 if (x < 0) return(x);
1718 debug(F101,"ackns winlo","",winlo);
1719 debug(F101,"ackns n","",n);
1720 if (n == winlo) { /* If we're acking winlo */
1721 if (k > -1)
1722 freerbuf(k); /* don't need it any more */
1723 if (j > -1)
1724 freesbuf(j); /* and don't need to keep ACK either */
1725 winlo = (winlo + 1) % 64;
1726 }
1727 return(0);
1728 }
1729
1730 int
ackn(n)1731 ackn(n) int n; { /* Send ACK for packet number n */
1732 return(ackns(n,(CHAR *)""));
1733 }
1734
1735 int
ack1(s)1736 ack1(s) CHAR *s; { /* Send an ACK with data. */
1737 if (!s) s = (CHAR *)"";
1738 debug(F110,"ack1",(char *)s,0);
1739 return(ackns(winlo,s));
1740 }
1741
1742 /* N A C K -- Send a Negative ACKnowledgment. */
1743 /*
1744 Call with the packet number, n, to be NAK'd.
1745 Returns -1 if that packet has been NAK'd too many times, otherwise 0.
1746 Btw, it is not right to return 0 under error conditions. This is
1747 done because the -1 code is used for cancelling the file transfer.
1748 More work is needed here.
1749 */
1750 int
nack(n)1751 nack(n) int n; {
1752 int i, x;
1753
1754 if (n < 0 || n > 63) {
1755 debug(F101,"nack bad pkt num","",n);
1756 return(0);
1757 } else debug(F101,"nack","",n);
1758 if ((i = sseqtbl[n]) < 0) { /* If necessary */
1759 if (getsbuf(n) < 0) { /* get a buffer for this NAK */
1760 debug(F101,"nack can't getsbuf","",n);
1761 return(0);
1762 } else i = sseqtbl[n]; /* New slot number */
1763 }
1764 if (maxtry > 0 && s_pkt[i].pk_rtr++ > maxtry) /* How many? */
1765 return(-1); /* Too many... */
1766
1767 /* Note, don't free this buffer. Eventually an ACK will come, and that */
1768 /* will set it free. If not, well, it's back to ground zero anyway... */
1769
1770 x = spack('N',n,0,(CHAR *) ""); /* NAKs never have data. */
1771 return(x);
1772 }
1773
1774 #ifndef NEWDPL /* This routine no longer used */
1775 /*
1776 * (PWP) recalculate the optimal packet length in the face of errors.
1777 * This is a modified version of the algorithm by John Chandler in Kermit/370,
1778 * see "Dynamic Packet Size Control", Kermit News, V2 #1, June 1988.
1779 *
1780 * This implementation minimizes the total overhead equation, which is
1781 *
1782 * Total chars = file_chars + (header_len * num_packs)
1783 * + (errors * (header_len + packet_len))
1784 *
1785 * Differentiate with respect to number of chars, solve for packet_len, get:
1786 *
1787 * packet_len = sqrt (file_chars * header_len / errors)
1788 */
1789
1790 /*
1791 (FDC) New super-simple algorithm. If there was an error in the most recent
1792 packet exchange, cut the send-packet size in half, down to a minimum of 20.
1793 If there was no error, increase the size by 5/4, up to the maximum negotiated
1794 length. Seems to be much more responsive than previous algorithm, which took
1795 forever to recover the original packet length, and it also went crazy under
1796 certain conditions.
1797
1798 Here's another idea for packet length resizing that keeps a history of the
1799 last n packets. Push a 1 into the left end of an n-bit shift register if the
1800 current packet is good, otherwise push a zero. The current n-bit value, w, of
1801 this register is a weighted sum of the noise hits for the last n packets, with
1802 the most recent weighing the most. The current packet length is some function
1803 of w and the negotiated packet length, like:
1804
1805 (2^n - w) / (2^n) * (negotiated length)
1806
1807 If the present resizing method causes problems, think about this one a little
1808 more.
1809 */
1810 VOID
rcalcpsz()1811 rcalcpsz() {
1812
1813 #ifdef COMMENT
1814 /* Old way */
1815 register long x, q;
1816 if (numerrs == 0) return; /* bounds check just in case */
1817
1818 /* overhead on a data packet is npad+5+bctr, plus 3 if extended packet */
1819 /* an ACK is 5+bctr */
1820
1821 /* first set x = per packet overhead */
1822 if (wslots > 1) /* Sliding windows */
1823 x = (long) (npad+5+bctr); /* packet only, don't count ack */
1824 else /* Stop-n-wait */
1825 x = (long) (npad+5+3+bctr+5+bctr); /* count packet and ack. */
1826
1827 /* then set x = packet length ** 2 */
1828 x = x * ( ffc / (CK_OFF_T) numerrs); /* careful of overflow */
1829
1830 /* calculate the long integer sqrt(x) quickly */
1831 q = 500;
1832 q = (q + x/q) >> 1;
1833 q = (q + x/q) >> 1;
1834 q = (q + x/q) >> 1;
1835 q = (q + x/q) >> 1; /* should converge in about 4 steps */
1836 if ((q > 94) && (q < 130)) /* break-even point for long packets */
1837 q = 94;
1838 if (q > spmax) q = spmax; /* maximum bounds */
1839 if (q < 10) q = 10; /* minimum bounds */
1840 spsiz = q; /* set new send packet size */
1841 debug(F101,"rcalcpsiz","",q);
1842 #else
1843 /* New way */
1844 debug(F101,"rcalcpsiz numerrs","",numerrs);
1845 debug(F101,"rcalcpsiz spsiz","",spsiz);
1846 if (spackets < 3) {
1847 numerrs = 0;
1848 return;
1849 }
1850 if (numerrs)
1851 spsiz = spsiz / 2;
1852 else
1853 spsiz = (spsiz / 4) * 5;
1854 if (spsiz < 20) spsiz = 20;
1855 if (spsiz > spmax) spsiz = spmax;
1856 debug(F101,"rcalcpsiz new spsiz","",spsiz);
1857 numerrs = 0;
1858 #endif /* COMMENT */
1859 }
1860 #endif /* NEWDPL */
1861
1862 /* R E S E N D -- Retransmit packet n. */
1863
1864 /*
1865 Returns 0 or positive on success (the number of retries for packet n).
1866 On failure, returns a negative number, and an error message is placed
1867 in recpkt.
1868 */
1869 int
resend(n)1870 resend(n) int n; { /* Send packet n again. */
1871 int j, k, x;
1872 #ifdef GFTIMER
1873 CKFLOAT t1 = 0.0, t2 = 0.0;
1874 #endif /* GFTIMER */
1875
1876 debug(F101,"resend seq","",n);
1877
1878 k = chkwin(n,winlo,wslots); /* See if packet in current window */
1879 j = -1; /* Assume it's lost */
1880 if (k == 0) j = sseqtbl[n]; /* See if we still have a copy of it */
1881 if (k != 0 || j < 0) { /* If not.... */
1882 if (nakstate && k == 1) {
1883 /*
1884 Packet n is in the previous window and we are the file receiver.
1885 We already sent the ACK and deallocated its buffer so we can't just
1886 retransmit the ACK. Rather than give up, we try some tricks...
1887 */
1888 if (n == 0 && spackets < 63 && myinit[0]) { /* ACK to Send-Init */
1889 /*
1890 If the packet number is 0, and we're at the beginning of a protocol
1891 operation (spackets < 63), then we have to resend the ACK to an I or S
1892 packet, complete with parameters in the data field. So we take a chance and
1893 send a copy of the parameters in an ACK packet with block check type 1.
1894 (Or 3 if SET BLOCK 5.)
1895 */
1896 if (bctf) { /* Force Type 3 on all packets? */
1897 x = spack('Y',0,(int)strlen((char *)myinit),(CHAR *)myinit);
1898 if (x < 0) return(x);
1899 logpkt('#',n,(CHAR *)"<reconstructed>",0); /* Log it */
1900 } else { /* Regular Kermit protocol */
1901 int bctlsav; /* Temporary storage */
1902 int bctusav;
1903 bctlsav = bctl; /* Save current block check length */
1904 bctusav = bctu; /* and type */
1905 bctu = bctl = 1; /* Set block check to 1 */
1906 x = spack('Y',0,(int)strlen((char *)myinit),(CHAR *)myinit);
1907 if (x < 0) return(x);
1908 logpkt('#',n,(CHAR *)"<reconstructed>",0); /* Log it */
1909 bctu = bctusav; /* Restore block check type */
1910 bctl = bctlsav; /* and length */
1911 }
1912 } else { /* Not the first packet */
1913 /*
1914 It's not the first packet of the protocol operation. It's some other packet
1915 that we have already ACK'd and forgotten about. So we take a chance and
1916 send an empty ACK using the current block-check type. Usually this will
1917 work out OK (like when acking Data packets), and no great harm will be done
1918 if it was some other kind of packet (F, etc). If we are requesting an
1919 interruption of the file transfer, the flags are still set, so we'll catch
1920 up on the next packet.
1921 */
1922 x = spack('Y',n,0,(CHAR *) "");
1923 if (x < 0) return(x);
1924 }
1925 retrans++;
1926 xxscreen(SCR_PT,'%',(long)pktnum,"Retransmission");
1927 return(0);
1928 } else {
1929 /*
1930 Packet number is not in current or previous window. We seem to hit this
1931 code occasionally at the beginning of a transaction, for apparently no good
1932 reason. Let's just log it for debugging, send nothing, and try to proceed
1933 with the protocol rather than killing it.
1934 */
1935 debug(F101,"resend PKT NOT IN WINDOW","",n);
1936 debug(F101,"resend k","",k);
1937 return(0);
1938 }
1939 }
1940
1941 /* OK, it's in the window and it's not lost. */
1942
1943 debug(F101,"resend pktinfo index","",k);
1944
1945 if (maxtry > 0 && s_pkt[j].pk_rtr++ > maxtry) { /* Over retry limit */
1946 xitsta |= what;
1947 return(-1);
1948 }
1949 debug(F101,"resend retry","",s_pkt[j].pk_rtr); /* OK so far */
1950 dumpsbuf(); /* (debugging) */
1951 if (s_pkt[j].pk_typ == ' ') { /* Incompletely formed packet */
1952 if (nakstate) { /* (This shouldn't happen any more) */
1953 nack(n);
1954 retrans++;
1955 xxscreen(SCR_PT,'%',(long)pktnum,"(resend)");
1956 return(s_pkt[j].pk_rtr);
1957 } else { /* No packet to resend! */
1958 #ifdef COMMENT
1959 /*
1960 This happened (once) while sending a file with 2 window slots and typing
1961 X to the sender to cancel the file. But since we're cancelling anyway,
1962 there's no need to give a scary message.
1963 */
1964 sprintf((char *)epktmsg,
1965 "resend logic error: NPS, n=%d, j=%d.",n,j);
1966 return(-2);
1967 #else
1968 /* Just ignore it. */
1969 return(0);
1970 #endif /* COMMENT */
1971 }
1972 }
1973 #ifdef DEBUG
1974 #ifdef GFTIMER
1975 if (deblog) t1 = gftimer();
1976 #endif /* GFTIMER */
1977 #endif /* DEBUG */
1978
1979 /* Everything ok, send the packet */
1980 #ifdef CK_TIMERS
1981 if (timint > 0)
1982 srttbl[n] = gtimer(); /* Update the timer */
1983 #endif /* CK_TIMERS */
1984 x = ttol(s_pkt[j].pk_adr,s_pkt[j].pk_len);
1985
1986 #ifdef DEBUG
1987 #ifdef GFTIMER
1988 if (deblog) {
1989 t2 = gftimer();
1990 debug(F101,"resend ttol msec","",(long)((t2-t1)*1000.0));
1991 }
1992 #endif /* GFTIMER */
1993 #endif /* DEBUG */
1994 debug(F101,"resend ttol returns","",x);
1995
1996 retrans++; /* Count a retransmission */
1997 xxscreen(SCR_PT,'%',(long)pktnum,"(resend)"); /* Tell user about resend */
1998 logpkt('S',n,s_pkt[j].pk_adr, s_pkt[j].pk_len); /* Log the resent packet */
1999 return(s_pkt[j].pk_rtr); /* Return the number of retries. */
2000 }
2001
2002 /* E R R P K T -- Send an Error Packet */
2003
2004 int
errpkt(reason)2005 errpkt(reason) CHAR *reason; { /* ...containing the reason given */
2006 extern int rtimo, state, justone;
2007 int x, y;
2008 czseen = 1; /* Also cancels batch */
2009 state = 0; /* Reset protocol state */
2010 debug(F110,"errpkt",reason,0);
2011 tlog(F110,"Protocol Error:",(char *)reason,0L);
2012 xxscreen(SCR_EM,0,0L,reason);
2013 encstr(reason);
2014 x = spack('E',pktnum,size,data);
2015 ckstrncpy((char *)epktmsg,(char *)reason,PKTMSGLEN);
2016 y = quiet; quiet = 1; epktsent = 1; /* Close files silently. */
2017 clsif(); clsof(1);
2018 quiet = y;
2019 /*
2020 I just sent an E-packet. I'm in local mode, I was receiving a file,
2021 I'm not a server, and sliding windows are in use. Therefore, there are
2022 likely to be a bunch of packets already "in the pipe" on their way to me
2023 by the time the remote sender gets the E-packet. So the next time I
2024 CONNECT or try to start another protocol operation, I am likely to become
2025 terribly confused by torrents of incoming material. To prevent this,
2026 the following code soaks up packets from the connection until there is an
2027 error or timeout, without wasting too much time waiting.
2028
2029 Exactly the same problem occurs when I am in remote mode or if I am
2030 in server mode with the justone flag set. In remote mode not only
2031 does the packet data potentially get echo'd back to the sender which
2032 is confusing to the user in CONNECT mode, but it also may result in the
2033 host performing bizarre actions such as suspending the process if ^Z is
2034 unprefixed, etc.
2035
2036 Furthermore, thousands of packets bytes in the data stream prevent the
2037 client from being able to process Telnet Kermit Option negotiations
2038 properly.
2039 */
2040 #ifdef STREAMING
2041 /* Because streaming sets the timeout to 0... */
2042 if (streaming) {
2043 timint = rcvtimo = rtimo;
2044 streaming = 0;
2045 }
2046 #endif /* STREAMING */
2047 if (what & W_RECV &&
2048 (!server || (server && justone)) &&
2049 (wslots > 1
2050 #ifdef STREAMING
2051 || streaming
2052 #endif /* STREAMING */
2053 )) {
2054 #ifdef GFTIMER
2055 CKFLOAT oldsec, sec = (CKFLOAT) 0.0;
2056 #else
2057 int oldsec, sec = 0;
2058 #endif /* GFTIMER */
2059 debug(F101,"errpkt draining","",wslots);
2060 xxscreen(SCR_ST,ST_MSG,0l,"Draining incoming packets, wait...");
2061 while (x > -1) { /* Don't bother if no connection */
2062 oldsec = sec;
2063 #ifdef GFTIMER
2064 sec = gftimer();
2065 if (oldsec != (CKFLOAT) 0.0)
2066 timint = rcvtimo = (int) (sec - oldsec + 0.5);
2067 #else
2068 sec = gtimer();
2069 if (oldsec != 0)
2070 timint = rcvtimo = sec - oldsec + 1;
2071 #endif /* GFTIMER */
2072 if (timint < 1)
2073 timint = rcvtimo = 1;
2074 msleep(50); /* Allow a bit of slop */
2075 x = rpack(); /* Read a packet */
2076 if (x == 'T' || x == 'z') /* Timed out means we're done */
2077 break;
2078 xxscreen(SCR_PT,x,rsn,""); /* Let user know */
2079 }
2080 xxscreen(SCR_ST,ST_MSG,0l,"Drain complete.");
2081 }
2082 if ((x = (what & W_KERMIT)))
2083 xitsta |= x; /* Remember what failed. */
2084 success = 0;
2085 return(y);
2086 }
2087
2088 /* scmd() -- Send a packet of the given type */
2089
2090 int
2091 #ifdef CK_ANSIC
scmd(char t,CHAR * dat)2092 scmd(char t, CHAR *dat)
2093 #else
2094 scmd(t,dat) char t; CHAR *dat;
2095 #endif /* CK_ANSIC */
2096 /* scmd */ {
2097 int x;
2098 extern char * srimsg;
2099 debug(F000,"scmd",dat,t);
2100 if (encstr(dat) < 0) { /* Encode the command string */
2101 srimsg = "String too long";
2102 return(-1);
2103 }
2104 x = spack(t,pktnum,size,data);
2105 debug(F101,"scmd spack","",x);
2106 return(x);
2107 }
2108
2109 /* Compose and Send GET packet */
2110
2111 struct opktparm { /* O-Packet item list */
2112 CHAR * opktitem;
2113 struct opktparm * opktnext;
2114 };
2115
2116 struct opktparm * opkthead = NULL; /* Linked list of O-packet fields */
2117 int opktcnt = 0; /* O-Packet counter */
2118 char * srimsg = NULL; /* GET-Packet error message */
2119
2120 /* S O P K T -- Send O-Packet */
2121 /*
2122 Sends one O-Packet each time called, using first-fit method of filling
2123 the packet from linked list of parameters pointed to by opkthead.
2124 To be called repeatedly until list is empty or there is an error.
2125 Returns:
2126 -1 on failure.
2127 0 on success and no more fields left to send.
2128 1 on success but with more fields left to be sent.
2129 */
2130
2131 int
sopkt()2132 sopkt() {
2133 int n = 0; /* Field number in this packet */
2134 int rc = 0; /* Return code */
2135 int len = 0; /* Data field length */
2136 char c = NUL;
2137 struct opktparm * o = NULL;
2138 struct opktparm * t = NULL;
2139 struct opktparm * prev = NULL;
2140 CHAR * dsave = data;
2141 int x, ssave = spsiz;
2142
2143 srimsg = NULL; /* Error message */
2144 o = opkthead; /* Point to head of list */
2145 if (!o) { /* Oops, no list... */
2146 srimsg = "GET Packet Internal Error 1";
2147 debug(F100,"sopkt NULL list","",0);
2148 return(-1);
2149 }
2150 while (o) { /* Go thru linked list... */
2151 c = *(o->opktitem); /* Parameter code */
2152 debug(F000,"sopkt",o->opktitem,c);
2153 x = encstr((CHAR *)o->opktitem);
2154 debug(F111,"sopkt encstr",dsave,x);
2155 if (x < 0) { /* Encode this item */
2156 if (n == 0) { /* Failure, first field in packet */
2157 debug(F100,"sopkt overflow","",0);
2158 spsiz = ssave; /* Restore these */
2159 data = dsave;
2160 o = opkthead; /* Free linked list */
2161 while (o) {
2162 if (o->opktitem) free(o->opktitem);
2163 t = o->opktnext;
2164 free((char *)o);
2165 o = t;
2166 }
2167 opkthead = NULL;
2168 srimsg = "GET Packet Too Long for Server";
2169 return(-1); /* Fail */
2170 } else { /* Not first field in packet */
2171 debug(F110,"sopkt leftover",o->opktitem,0);
2172 prev = o; /* Make this one the new previous */
2173 o = o->opktnext; /* Get next */
2174 c = NUL; /* So we know we're not done */
2175 *data = NUL; /* Erase any partial encoding */
2176 continue; /* We can try this one again later */
2177 }
2178 }
2179 n++; /* Encoding was successful */
2180 debug(F111,"sopkt field",data,x);
2181 len += x; /* Total data field length */
2182 data += x; /* Set up for next field... */
2183 spsiz -= x;
2184 free(o->opktitem); /* Free item just encoded */
2185 if (o == opkthead) { /* If head */
2186 opkthead = o->opktnext; /* Move head to next */
2187 free((char *)o); /* Free this list node */
2188 o = opkthead;
2189 } else { /* If not head */
2190 o = o->opktnext; /* Get next */
2191 prev->opktnext = o; /* Link previous to next */
2192 }
2193 if (c == '@') /* Loop exit */
2194 break;
2195 if (!o && !opkthead) { /* Set up End Of Parameters Field */
2196 o = (struct opktparm *)malloc(sizeof(struct opktparm));
2197 if (o) {
2198 opkthead = o;
2199 if (!(o->opktitem = (CHAR *)malloc(3))) {
2200 free((char *)o);
2201 srimsg = "GET Packet Internal Error 8";
2202 return(-1);
2203 }
2204 ckstrncpy((char *)(o->opktitem), "@ ", 3);
2205 debug(F111,"sopkt o->opktitem",o->opktitem,
2206 strlen((char *)(o->opktitem)));
2207 o->opktnext = NULL;
2208 }
2209 }
2210 }
2211 data = dsave; /* Restore globals */
2212 spsiz = ssave;
2213 debug(F110,"sopkt data",data,0);
2214 debug(F101,"sopkt opktcnt","",opktcnt);
2215 if (opktcnt++ > 0) {
2216 if (nxtpkt() < 0) { /* Get next packet number and buffer */
2217 srimsg = "GET Packet Internal Error 9";
2218 return(-1);
2219 }
2220 }
2221 debug(F101,"sopkt pktnum","",pktnum);
2222 rc = spack((char)'O',pktnum,len,data); /* Send O-Packet */
2223 debug(F101,"sopkt spack","",rc);
2224 if (rc < 0) /* Failed */
2225 srimsg = "Send Packet Failure"; /* Set message */
2226 else /* Succeeded */
2227 rc = (c == '@') ? 0 : 1; /* 1 = come back for more, 0 = done */
2228 debug(F101,"sopkt rc","",rc);
2229 return(rc);
2230 }
2231
2232 /* S R I N I T -- Send GET packet */
2233 /*
2234 Sends the appropriate GET-Class packet.
2235 Returns:
2236 -1 on error
2237 0 if packet sent successfully and we can move on to the next state
2238 1 if an O-packet was sent OK but more O packets still need to be sent.
2239 */
2240 int
srinit(reget,retrieve,opkt)2241 srinit(reget, retrieve, opkt) int reget, retrieve, opkt; {
2242 int x = 0, left = 0;
2243 extern int oopts, omode;
2244 CHAR * p = NULL;
2245 #ifdef RECURSIVE
2246 extern int recursive;
2247 debug(F101,"srinit recursive","",recursive);
2248 #endif /* RECURSIVE */
2249 debug(F101,"srinit reget","",reget);
2250 debug(F101,"srinit retrieve","",retrieve);
2251 debug(F101,"srinit opkt","",opkt);
2252 debug(F101,"srinit oopts","",oopts);
2253 debug(F101,"srinit omode","",omode);
2254 debug(F110,"srinit cmarg",cmarg,0);
2255 srimsg = NULL;
2256
2257 opktcnt = 0;
2258 if (!cmarg) cmarg = "";
2259 if (!*cmarg) {
2260 srimsg = "GET with no filename";
2261 debug(F100,"srinit null cmarg","",0);
2262 return(-1);
2263 }
2264 if (opkt) { /* Extended GET is totally different */
2265 char buf[16];
2266 struct opktparm * o = NULL;
2267 struct opktparm * prev = NULL;
2268
2269 buf[0] = NUL;
2270
2271 /* Build O-Packet fields and send (perhaps first) O-Packet */
2272
2273 if (oopts > -1) { /* Write Option flags */
2274 o = (struct opktparm *)malloc(sizeof(struct opktparm));
2275 if (!o) {
2276 srimsg = "GET Packet Internal Error 2";
2277 debug(F100,"srinit malloc fail O1","",0);
2278 return(-1);
2279 }
2280 sprintf(buf,"Ox%d",oopts); /* safe */
2281 x = (int) strlen(buf+2);
2282 buf[1] = tochar(x);
2283 o->opktitem = (CHAR *)malloc(x + 3);
2284 if (!o->opktitem) {
2285 srimsg = "GET Packet Internal Error 3";
2286 debug(F100,"srinit malloc fail O2","",0);
2287 return(-1);
2288 }
2289 ckstrncpy((char *)(o->opktitem),buf,x+3);
2290 o->opktnext = NULL;
2291 if (!opkthead)
2292 opkthead = o;
2293 prev = o;
2294 }
2295 if (omode > -1) { /* If Xfer Mode specified, write it */
2296 o = (struct opktparm *)malloc(sizeof(struct opktparm));
2297 if (!o) {
2298 srimsg = "GET Packet Internal Error 4";
2299 debug(F100,"srinit malloc fail M1","",0);
2300 return(-1);
2301 }
2302 sprintf(buf,"Mx%d",omode); /* safe */
2303 x = (int) strlen(buf+2);
2304 buf[1] = tochar(x);
2305 o->opktitem = (CHAR *)malloc(x + 3);
2306 if (!o->opktitem) {
2307 srimsg = "GET Packet Internal Error 5";
2308 debug(F100,"srinit malloc fail O2","",0);
2309 return(-1);
2310 }
2311 ckstrncpy((char *)(o->opktitem),buf,x+3);
2312 o->opktnext = NULL;
2313 if (!opkthead)
2314 opkthead = o;
2315 else
2316 prev->opktnext = o;
2317 prev = o;
2318 }
2319
2320 /* Same deal for oname and opath eventually but not needed now... */
2321
2322 x = strlen(cmarg); /* Now do filename */
2323 if (x > spsiz - 4) {
2324 srimsg = "GET Packet Too Long for Server";
2325 return(-1);
2326 }
2327 o = (struct opktparm *)malloc(sizeof(struct opktparm));
2328 if (!o) {
2329 srimsg = "GET Packet Internal Error 6";
2330 debug(F100,"srinit malloc fail F1","",0);
2331 return(-1);
2332 }
2333 left = x + 6;
2334 o->opktitem = (CHAR *)malloc(left + 1);
2335 if (!o->opktitem) {
2336 srimsg = "GET Packet Internal Error 7";
2337 debug(F100,"srinit malloc fail F2","",0);
2338 return(-1);
2339 }
2340 p = o->opktitem;
2341 *p++ = 'F';
2342 left--;
2343 if (x > 94) { /* Too long for normal length */
2344 *p++ = SYN; /* Escape length with Ctrl-V */
2345 *p++ = tochar(x / 95);
2346 *p++ = tochar(x % 95);
2347 left -= 3;
2348 } else { /* Normal encoding for 94 or less */
2349 *p++ = tochar(x);
2350 left--;
2351 }
2352 ckstrncpy((char *)p,cmarg,left); /* Copy the filename */
2353 o->opktnext = NULL;
2354 if (!opkthead)
2355 opkthead = o;
2356 else
2357 prev->opktnext = o;
2358 prev = o;
2359
2360 /* End of Parameters */
2361
2362 prev->opktnext = NULL; /* End of list. */
2363 return(sopkt());
2364 }
2365
2366 /* Not Extended GET */
2367
2368 if (encstr((CHAR *)cmarg) < 0) { /* Encode the filename. */
2369 srimsg = "GET Packet Too Long for Server";
2370 return(-1);
2371 }
2372 if (retrieve) { /* Send the packet. */
2373 #ifdef RECURSIVE
2374 if (recursive)
2375 x = spack((char)'W',pktnum,size,data); /* GET /DELETE /RECURSIVE */
2376 else
2377 #endif /* RECURSIVE */
2378 x = spack((char)'H',pktnum,size,data); /* GET /DELETE */
2379 }
2380 #ifdef RECURSIVE
2381 else if (recursive)
2382 x = spack((char)'V',pktnum,size,data); /* GET /RECURSIVE */
2383 #endif /* RECURSIVE */
2384 else
2385 x = spack((char)(reget ? 'J' : 'R'),pktnum,size,data); /* GET */
2386 if (x < 0)
2387 srimsg = "Send Packet Failure";
2388 return(x < 0 ? x : 0);
2389 }
2390
2391
2392 /* K S T A R T -- Checks for a Kermit packet while in terminal mode. */
2393
2394 /* (or command mode...) */
2395
2396 #ifdef CK_AUTODL
2397 int
2398 #ifdef CK_ANSIC
kstart(CHAR ch)2399 kstart(CHAR ch)
2400 #else
2401 kstart(ch) CHAR ch;
2402 #endif /* CK_ANSIC */
2403 /* kstart */ {
2404 static CHAR * p = NULL;
2405
2406 #ifdef OS2
2407 static CHAR * pk = NULL;
2408 #endif /* OS2 */
2409 ch &= 0177; /* Strip 8th bit */
2410
2411 /* Because we're in cooked mode at the command prompt... */
2412
2413 if (ch == LF) {
2414 debug(F110,"kstart","ch == LF",0);
2415 if ((what == W_COMMAND || what == W_INIT || what == W_NOTHING)) {
2416 if (eol == CR) {
2417 ch = eol;
2418 debug(F110,"kstart","ch = CR",0);
2419 }
2420 }
2421 }
2422
2423 #ifdef OS2
2424 if (adl_kmode == ADL_STR) {
2425 if (!ch)
2426 return(0);
2427 if (!pk)
2428 pk = adl_kstr;
2429
2430 if (ch == *pk) {
2431 pk++;
2432 if (*pk == '\0') {
2433 pk = adl_kstr;
2434 debug(F100, "kstart Kermit Start String","",0);
2435 return(PROTO_K + 1);
2436 }
2437 } else
2438 pk = adl_kstr;
2439 }
2440 #endif /* OS2 */
2441
2442 if (ch == stchr) { /* Start of packet */
2443 kstartactive = 1;
2444 p = ksbuf;
2445 *p = ch;
2446 debug(F101,"kstart SOP","",ch);
2447 } else if (ch == eol) { /* End of packet */
2448 kstartactive = 0;
2449 if (p) {
2450 debug(F101,"kstart EOL","",ch);
2451 p++;
2452 if (p - ksbuf < 94 ) {
2453 int rc = 0;
2454 *p++ = ch;
2455 *p = NUL;
2456 rc = chkspkt((char *)ksbuf);
2457 debug(F111,"kstart EOP chkspkt", ksbuf, rc);
2458 p = NULL;
2459 if (!rc) return(0);
2460 if (rc == 2) rc = -1;
2461 debug(F111,"kstart ksbuf",ksbuf,rc);
2462 return(rc);
2463 } else {
2464 debug(F110,"kstart","p - ksbuf >= 94",0);
2465 p = NULL;
2466 }
2467 }
2468 } else if (p) {
2469 if (ch < SP)
2470 kstartactive = 0;
2471 p++;
2472 if (p - ksbuf < 94) {
2473 *p = ch;
2474 } else {
2475 p = NULL;
2476 debug(F110,"kstart","p - ksbuf >= 94",0);
2477 }
2478 }
2479 return(0);
2480 }
2481
2482 #ifdef CK_XYZ
2483
2484 /* Z S T A R T -- Checks for a ZMODEM packet while in terminal mode. */
2485
2486 int
2487 #ifdef CK_ANSIC
zstart(CHAR ch)2488 zstart(CHAR ch)
2489 #else
2490 zstart(ch) CHAR ch;
2491 #endif /* CK_ANSIC */
2492 /* zstart */ {
2493 static CHAR * matchstr = (CHAR *) "\030B00";
2494 /* "rz\r**\030B00000000000000\r\033J\021"; */
2495 static CHAR * p = NULL;
2496 extern int inserver;
2497
2498 if (inserver)
2499 return(0);
2500
2501 if (!ch)
2502 return(0);
2503 if (!p) {
2504 #ifdef OS2
2505 p = adl_zmode == ADL_PACK ? matchstr : adl_zstr;
2506 #else
2507 p = matchstr;
2508 #endif /* OS2 */
2509 }
2510 if (ch == *p) {
2511 p++;
2512 if (*p == '\0') {
2513 #ifdef OS2
2514 if (adl_zmode == ADL_PACK) {
2515 p = matchstr;
2516 debug(F100, "zstart Zmodem SOP","",0);
2517 } else {
2518 p = adl_zstr;
2519 debug(F100, "zstart Zmodem Start String","",0);
2520 }
2521 #else
2522 p = matchstr;
2523 debug(F100, "zstart Zmodem SOP","",0);
2524 #endif /* OS2 */
2525 return(PROTO_Z + 1);
2526 }
2527 } else {
2528 #ifdef OS2
2529 p = adl_zmode == ADL_PACK ? matchstr : adl_zstr;
2530 #else
2531 p = matchstr;
2532 #endif /* OS2 */
2533 }
2534 return(0);
2535 }
2536 #endif /* CK_XYZ */
2537
2538 #ifndef NOICP
2539 #ifdef CK_APC
2540 /* A U T O D O W N */
2541
2542 #ifdef CK_ANSIC
2543 VOID
autodown(int ch)2544 autodown(int ch)
2545 #else
2546 VOID
2547 autodown(ch) int ch;
2548 #endif /* CK_ANSIC */
2549 /* autodown */ {
2550
2551 /* The Kermit and Zmodem Auto-download calls go here */
2552
2553 extern int justone; /* From protocol module */
2554 extern int debses, protocol, apcactive, autodl, inautodl;
2555 #ifdef DCMDBUF
2556 extern char *apcbuf;
2557 #else
2558 extern char apcbuf[];
2559 #endif /* DCMDBUF */
2560 #ifdef OS2
2561 extern int apclength, term_io;
2562 #endif /* OS2 */
2563 int k = 0;
2564
2565 if ((autodl || inautodl
2566 #ifdef IKS_OPTION
2567 || TELOPT_SB(TELOPT_KERMIT).kermit.me_start
2568 #endif /* IKS_OPTION */
2569 ) && !debses) {
2570 #ifdef CK_XYZ
2571 #ifdef XYZ_INTERNAL
2572 extern int p_avail;
2573 #else
2574 int p_avail = 1;
2575 #endif /* XYZ_INTERNAL */
2576 if (p_avail && zstart((CHAR) ch)) {
2577 debug(F100, "Zmodem download","",0);
2578 #ifdef OS2
2579 #ifndef NOTERM
2580 apc_command(APC_LOCAL,"receive /protocol:zmodem");
2581 #endif /* NOTERM */
2582 #else /* OS2 */
2583 ckstrncpy(apcbuf,"receive /protocol:zmodem",APCBUFLEN);
2584 apcactive = APC_LOCAL;
2585 #endif /* OS2 */
2586 return;
2587 }
2588 #endif /* CK_XYZ */
2589
2590 /* First try... */
2591 k = kstart((CHAR) ch);
2592 if (
2593 #ifdef NOSERVER
2594 k > 0
2595 #else /* NOSERVER */
2596 k
2597 #endif /* NOSERVER */
2598 ) { /* We saw a valid S or I packet */
2599 if (k < 0) { /* Stuff RECEIVE into APC buffer */
2600 justone = 1;
2601 switch (protocol) {
2602 #ifdef CK_XYZ
2603 case PROTO_G:
2604 ckstrncpy(apcbuf,
2605 "set proto kermit, server, set protocol g",
2606 APCBUFLEN
2607 );
2608 break;
2609 case PROTO_X:
2610 ckstrncpy(apcbuf,
2611 "set proto kermit,server,set proto xmodem",
2612 APCBUFLEN
2613 );
2614 break;
2615 case PROTO_XC:
2616 ckstrncpy(apcbuf,
2617 "set proto kermit,server,set proto xmodem-crc",
2618 APCBUFLEN
2619 );
2620 break;
2621 case PROTO_Y:
2622 ckstrncpy(apcbuf,
2623 "set proto kermit,server, set protocol y",
2624 APCBUFLEN
2625 );
2626 break;
2627 case PROTO_Z:
2628 ckstrncpy(apcbuf,
2629 "set proto kermit,server,set proto zmodem",
2630 APCBUFLEN
2631 );
2632 break;
2633 #endif /* CK_XYZ */
2634 case PROTO_K:
2635 ckstrncpy(apcbuf,"server",APCBUFLEN);
2636 break;
2637 }
2638 } else {
2639 justone = 0;
2640 ckstrncpy(apcbuf,"receive /protocol:kermit",APCBUFLEN);
2641 }
2642 #ifdef OS2
2643 #ifndef NOTERM
2644 apc_command(APC_LOCAL,apcbuf);
2645 #endif /* NOTERM */
2646 #else /* OS2 */
2647 ckstrncpy(apcbuf,"receive /protocol:zmodem",APCBUFLEN);
2648 apcactive = APC_LOCAL;
2649 #endif /* OS2 */
2650 return;
2651 }
2652 }
2653 }
2654 #endif /* CK_APC */
2655 #endif /* NOICP */
2656
2657 /* C H K S P K T -- Check if buf contains a valid S or I packet */
2658
2659 int
chkspkt(packet)2660 chkspkt(packet) char *packet; {
2661 int i;
2662 int buflen;
2663 int len = -1;
2664 CHAR chk;
2665 char type = 0;
2666 char *s = NULL;
2667 char *buf = NULL;
2668 char tmpbuf[100]; /* Longest S/I packet is about 30 */
2669
2670 if (!packet) return(0);
2671 buflen = ckstrncpy(tmpbuf,packet,100); /* Make a pokeable copy */
2672 if (buflen < 5) return(0); /* Too short */
2673 if (buflen > 100) return(0); /* Too long to be an S or I packet */
2674 s = buf = tmpbuf; /* Point to beginning of copy */
2675
2676 if (*s++ != stchr) return(0); /* SOH */
2677 len = xunchar(*s++); /* Length */
2678 if (len < 0) return(0);
2679 if (*s++ != SP) return(0); /* Sequence number */
2680 type = *s++; /* Type */
2681 if (type != 'S' && type != 'I')
2682 return(0);
2683 if (buflen < len + 2) return(0);
2684 s += (len - 3); /* Position of checksum */
2685 chk = (CHAR) (*s); /* Checksum */
2686 *s = NUL; /* Temporarily null-terminate data field */
2687 if (xunchar(chk) != chk1((CHAR *)(buf+1),buflen-2)) { /* Check it */
2688 /*
2689 In C-Kermit 9.0 and later, an S or I packet can have a
2690 Type 3 Block check ("help set block-check" for details).
2691 */
2692 unsigned crc; /* Failed... Try Type 3 block check */
2693 *s = chk; /* Replace last byte */
2694 s -= 2; /* Back up two bytes */
2695 crc = (xunchar(s[0]) << 12) /* Convert 3 bytes to numeric CRC */
2696 | (xunchar(s[1]) << 6)
2697 | (xunchar(s[2]));
2698 chk = (CHAR)(*s); /* Copy 1st byte of 3-byte CRC */
2699 *s = NUL; /* Null-terminate data field */
2700 if (crc != chk3((CHAR *)(buf+1),strlen(buf+1)))
2701 return(0);
2702 }
2703 return(type == 'S' ? 1 : 2);
2704 }
2705 #endif /* CK_AUTODL */
2706
2707 /* R P A C K -- Read a Packet */
2708
2709 /*
2710 rpack reads a packet and returns the packet type, or else Q if the
2711 packet was invalid, or T if a timeout occurred. Upon successful return,
2712 sets the values of global rsn (received sequence number), rln (received
2713 data length), and rdatap (pointer to null-terminated data field), and
2714 returns the packet type. NOTE: This is an inner-loop function so must be
2715 efficient. Protect function calls by if-tests where possible, e.g.
2716 "if (pktlog) logpkt(...);".
2717 */
2718 int
rpack()2719 rpack() {
2720 register int i, j, x, lp; /* Local variables */
2721 #ifdef CKTUNING
2722 unsigned int chk;
2723 #endif /* CKTUNING */
2724 int k, type, chklen;
2725 unsigned crc;
2726 CHAR pbc[5]; /* Packet block check */
2727 CHAR *sohp; /* Pointer to SOH */
2728 CHAR e; /* Packet end character */
2729
2730 #ifdef GFTIMER
2731 CKFLOAT t1 = 0.0, t2 = 0.0;
2732 #endif /* GFTIMER */
2733
2734 debug(F101,"rpack pktnum","",pktnum);
2735
2736 #ifndef OLDCHKINT
2737 if (chkint() < 0) /* Check for console interrupts. */
2738 return('z');
2739 #endif /* OLDCHKINT */
2740
2741 k = getrbuf(); /* Get a new packet input buffer. */
2742 debug(F101,"rpack getrbuf","",k);
2743 if (k < 0) { /* Return like this if none free. */
2744 return(-1);
2745 }
2746 recpkt = r_pkt[k].bf_adr;
2747 *recpkt = '\0'; /* Clear receive buffer. */
2748 sohp = recpkt; /* Initialize pointers to it. */
2749 rdatap = recpkt;
2750 rsn = rln = -1; /* In case of failure. */
2751 e = (turn) ? turnch : eol; /* Use any handshake char for eol */
2752
2753 /* Try to get a "line". */
2754
2755 #ifdef CK_AUTODL
2756 debug(F110,"rpack ksbuf",ksbuf,0);
2757 if (ksbuf[0]) { /* Kermit packet already */
2758 int x; /* collected for us in CONNECT mode */
2759 CHAR *s1 = recpkt, *s2 = ksbuf;
2760 j = 0;
2761 while (*s2) { /* Copy and get length */
2762 *s1++ = *s2++; /* No point optimizing this since */
2763 j++; /* it's never more than ~20 chars */
2764 }
2765 *s1 = NUL;
2766 #ifdef PARSENSE
2767 x = parchk(recpkt, stchr, j); /* Check parity */
2768 debug(F000,"autodownload parity","",parity);
2769 debug(F000,"autodownload parchk","",x);
2770 if (x > 0 && parity != x) {
2771 autopar = 1;
2772 parity = x;
2773 }
2774 #endif /* PARSENSE */
2775 ksbuf[0] = NUL; /* Don't do this next time! */
2776
2777 } else { /* Normally go read a packet */
2778 #endif /* CK_AUTODL */
2779
2780 #ifdef DEBUG
2781 if (deblog) {
2782 debug(F101,"rpack timint","",timint);
2783 debug(F101,"rpack rcvtimo","",rcvtimo);
2784 #ifdef STREAMING
2785 debug(F101,"rpack streaming","",streaming);
2786 #endif /* STREAMING */
2787 #ifdef GFTIMER
2788 /* Measure how long it takes to read a packet */
2789 t1 = gftimer();
2790 #endif /* GFTIMER */
2791 }
2792 #endif /* DEBUG */
2793
2794 /* JUST IN CASE (otherwise this could clobber streaming) */
2795
2796 if ((timint == 0
2797 #ifdef STREAMING
2798 || streaming
2799 #endif /* STREAMING */
2800 ) && (rcvtimo != 0)) {
2801 debug(F101,"rpack timint 0 || streaming but rcvtimo","",rcvtimo);
2802 rcvtimo = 0;
2803 }
2804
2805 #ifdef PARSENSE
2806 #ifdef UNIX
2807 /*
2808 So far the final turn argument is only for ck[uvdl]tio.c. Should be added
2809 to the others too. (turn == handshake character.)
2810 */
2811 j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn);
2812 #else
2813 #ifdef VMS
2814 j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn);
2815 #else
2816 #ifdef datageneral
2817 j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn);
2818 #else
2819 #ifdef STRATUS
2820 j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn);
2821 #else
2822 #ifdef OS2
2823 j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn);
2824 #else
2825 #ifdef OSK
2826 j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn);
2827 #else
2828 j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr);
2829 #endif /* OSK */
2830 #endif /* OS2 */
2831 #endif /* STRATUS */
2832 #endif /* datageneral */
2833 #endif /* VMS */
2834 #endif /* UNIX */
2835 if (parity != 0 && parity != 's' && ttprty != 0) {
2836 if (parity != ttprty) autopar = 1;
2837 parity = ttprty;
2838 }
2839 #else /* !PARSENSE */
2840 j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e);
2841 #endif /* PARSENSE */
2842
2843 #ifdef DEBUG
2844 if (deblog) {
2845 debug(F101,"rpack ttinl len","",j);
2846 #ifdef GFTIMER
2847 t2 = gftimer();
2848 debug(F101,"rpack ttinl msec","",(long)((t2-t1)*1000.0));
2849 #endif /* GFTIMER */
2850 }
2851 #endif /* DEBUG */
2852
2853 #ifdef STREAMING
2854 if (streaming && sndtyp == 'D' && j == 0)
2855 return('Y');
2856 #endif /* STREAMING */
2857
2858 if (j < 0) {
2859 /* -1 == timeout, -2 == ^C, -3 == connection lost or fatal i/o */
2860 debug(F101,"rpack: ttinl fails","",j); /* Otherwise, */
2861 freerbuf(k); /* Free this buffer */
2862 if (j < -1) { /* Bail out if ^C^C typed. */
2863 if (j == -2) {
2864 interrupted = 1;
2865 debug(F101,"rpack ^C server","",server);
2866 debug(F101,"rpack ^C en_fin","",en_fin);
2867 } else if (j == -3) {
2868 fatalio = 1;
2869 debug(F101,"rpack fatalio","",en_fin);
2870 }
2871 return(j);
2872 }
2873 if (nakstate) /* j == -1 is a read timeout */
2874 xxscreen(SCR_PT,'T',(long)winlo,"");
2875 else
2876 xxscreen(SCR_PT,'T',(long)pktnum,"");
2877 logpkt('r',-1,(CHAR *)"<timeout>",0);
2878 if (flow == 1) ttoc(XON); /* In case of Xoff blockage. */
2879 return('T');
2880 }
2881 #ifdef CK_AUTODL
2882 }
2883 #endif /* CK_AUTODL */
2884
2885 rpktl = j;
2886 tlci += j; /* All OK, Count the characters. */
2887 flci += j;
2888
2889 /* Find start of packet */
2890
2891 #ifndef PARSENSE
2892 for (i = 0; (recpkt[i] != stchr) && (i < j); i++)
2893 sohp++; /* Find mark */
2894 if (i++ >= j) { /* Didn't find it. */
2895 logpkt('r',-1,"<timeout>",0);
2896 freerbuf(k);
2897 return('T');
2898 }
2899 #else
2900 i = 1; /* ttinl does this for us */
2901 #endif /* PARSENSE */
2902
2903 rpackets++; /* Count received packet. */
2904 lp = i; /* Remember LEN position. */
2905 if ((j = xunchar(recpkt[i++])) == 0) { /* Get packet length. */
2906 if ((j = lp+5) > MAXRP) { /* Long packet */
2907 return('Q'); /* Too long */
2908 }
2909
2910 #ifdef CKTUNING
2911 /* Save some function-call and loop overhead... */
2912 #ifdef COMMENT
2913 /* ttinl() already removed parity */
2914 if (parity)
2915 #endif /* COMMENT */
2916 chk = (unsigned) ((unsigned) recpkt[i-1] +
2917 (unsigned) recpkt[i] +
2918 (unsigned) recpkt[i+1] +
2919 (unsigned) recpkt[i+2] +
2920 (unsigned) recpkt[i+3]
2921 );
2922 #ifdef COMMENT
2923 else
2924 chk = (unsigned) ((unsigned) (recpkt[i-1] & 077) +
2925 (unsigned) (recpkt[i] & 077) +
2926 (unsigned) (recpkt[i+1] & 077) +
2927 (unsigned) (recpkt[i+2] & 077) +
2928 (unsigned) (recpkt[i+3] & 077)
2929 );
2930 #endif /* COMMENT */
2931 if (xunchar(recpkt[j]) != ((((chk & 0300) >> 6) + chk) & 077))
2932 #else
2933 x = recpkt[j]; /* Header checksum. */
2934 recpkt[j] = '\0'; /* Calculate & compare. */
2935 if (xunchar(x) != chk1(recpkt+lp,5))
2936 #endif /* CKTUNING */
2937 {
2938 freerbuf(k);
2939 logpkt('r',-1,(CHAR *)"<crunched:hdr>",0);
2940 xxscreen(SCR_PT,'%',(long)pktnum,"Bad packet header");
2941 return('Q');
2942 }
2943 #ifndef CKTUNING
2944 recpkt[j] = x; /* Checksum ok, put it back. */
2945 #endif /* CKTUNING */
2946 rln = xunchar(recpkt[j-2]) * 95 + xunchar(recpkt[j-1]) - bctl;
2947 j = 3; /* Data offset. */
2948 } else if (j < 3) {
2949 debug(F101,"rpack packet length less than 3","",j);
2950 freerbuf(k);
2951 logpkt('r',-1,(CHAR *)"<crunched:len>",0);
2952 xxscreen(SCR_PT,'%',(long)pktnum,"Bad packet length");
2953 return('Q');
2954 } else {
2955 rln = j - bctl - 2; /* Regular packet */
2956 j = 0; /* No extended header */
2957 }
2958 rsn = xunchar(recpkt[i++]); /* Sequence number */
2959 if (pktlog) /* Save a function call! */
2960 logpkt('r',rsn,sohp,rln+bctl+j+4);
2961 if (rsn < 0 || rsn > 63) {
2962 debug(F101,"rpack bad sequence number","",rsn);
2963 freerbuf(k);
2964 if (pktlog)
2965 logpkt('r',rsn,(CHAR *)"<crunched:seq>",0);
2966 xxscreen(SCR_PT,'%',(long)pktnum,"Bad sequence number");
2967 return('Q');
2968 }
2969 /*
2970 If this packet has the same type as the packet just sent, assume it is
2971 an echo and ignore it. Don't even bother with the block check calculation:
2972 even if the packet is corrupted, we don't want to NAK an echoed packet.
2973 Nor must we NAK an ACK or NAK.
2974 */
2975 type = recpkt[i++]; /* Get packet's TYPE field */
2976 if (type == sndtyp || (nakstate && (type == 'N' /* || type == 'Y' */ ))) {
2977 debug(F000,"rpack echo","",type); /* If it's an echo */
2978 freerbuf(k); /* Free this buffer */
2979 logpkt('#',rsn,(CHAR *)"<echo:ignored>",0);
2980 return('e'); /* Return special (lowercase) code */
2981 }
2982 /*
2983 Separate the data from the block check, accounting for the case where
2984 a packet was retransmitted after the block check switched. The "Type 3
2985 Forced" business is new to C-Kermit 9.0.
2986 */
2987 if (bctf) { /* Type 3 forced on all packets */
2988 bctl = chklen = 3;
2989 } else if ((type == 'I' || type == 'S')) { /* Otherwise... */
2990 if (recpkt[11] == '5') { /* Sender is forcing Type 3 */
2991 bctf = 1; /* So we will too */
2992 bctl = chklen = 3;
2993 debug(F100,"RECOGNIZE BLOCK CHECK TYPE 5","",0);
2994 } else { /* Normal case */
2995 /* I & S packets always have type 1 */
2996 chklen = 1;
2997 rln = rln + bctl - 1;
2998 }
2999 } else if (type == 'N') { /* A NAK packet never has data */
3000 chklen = xunchar(recpkt[lp]) - 2;
3001 if (chklen < 1 || chklen > 3) { /* JHD 13 Apr 2010 */
3002 debug(F101,"rpack bad nak chklen","",chklen);
3003 freerbuf(k);
3004 logpkt('r',-1,(CHAR *)"<crunched:chklen>",0);
3005 xxscreen(SCR_PT,'%',(long)pktnum,"(bad nak)");
3006 return('Q');
3007 }
3008 rln = rln + bctl - chklen;
3009 } else chklen = bctl;
3010 #ifdef DEBUG
3011 if (deblog) { /* Save 2 function calls */
3012 debug(F101,"rpack bctl","",bctl);
3013 debug(F101,"rpack chklen","",chklen);
3014 }
3015 #endif /* DEBUG */
3016 i += j; /* Buffer index of DATA field */
3017 rdatap = recpkt+i; /* Pointer to DATA field */
3018 if ((j = rln + i) > r_pkt[k].bf_len) { /* Make sure it fits */
3019 debug(F101,"packet too long","",j);
3020 freerbuf(k);
3021 logpkt('r',rsn,(CHAR *)"<overflow>",0);
3022 return('Q');
3023 }
3024 for (x = 0; x < chklen; x++) /* Copy the block check */
3025 pbc[x] = recpkt[j+x]; /* 3 bytes at most. */
3026 pbc[x] = '\0'; /* Null-terminate block check string */
3027 recpkt[j] = '\0'; /* and the packet Data field. */
3028
3029 if (chklen == 2 && bctu == 4) { /* Adjust for Blank-Free-2 */
3030 chklen = 4; /* (chklen is now a misnomer...) */
3031 debug(F100,"rpack block check B","",0);
3032 }
3033 switch (chklen) { /* Check the block check */
3034 case 1: /* Type 1, 6-bit checksum */
3035 if (xunchar(*pbc) != chk1(recpkt+lp,j-lp)) {
3036 #ifdef DEBUG
3037 if (deblog) {
3038 debug(F110,"checked chars",recpkt+lp,0);
3039 debug(F101,"block check (1)","",(int) xunchar(*pbc));
3040 debug(F101,"should be (1)","",chk1(recpkt+lp,j-lp));
3041 }
3042 #endif /* DEBUG */
3043 freerbuf(k);
3044 logpkt('r',-1,(CHAR *)"<crunched:chk1>",0);
3045 xxscreen(SCR_PT,'%',(long)pktnum,"Checksum error");
3046 return('Q');
3047 }
3048 break;
3049 case 2: /* Type 2, 12-bit checksum */
3050 x = xunchar(*pbc) << 6 | xunchar(pbc[1]);
3051 if (x != chk2(recpkt+lp,j-lp)) { /* No match */
3052 if (type == 'E') { /* Allow E packets to have type 1 */
3053 recpkt[j++] = pbc[0];
3054 recpkt[j] = '\0';
3055 if (xunchar(pbc[1]) == chk1(recpkt+lp,j-lp))
3056 break;
3057 else
3058 recpkt[--j] = '\0';
3059 }
3060 #ifdef DEBUG
3061 if (deblog) {
3062 debug(F110,"checked chars",recpkt+lp,0);
3063 debug(F101,"block check (2)","", x);
3064 debug(F101,"should be (2)","", (int) chk2(recpkt+lp,j-lp));
3065 }
3066 #endif /* DEBUG */
3067 freerbuf(k);
3068 logpkt('r',-1,(CHAR *)"<crunched:chk2>",0);
3069 xxscreen(SCR_PT,'%',(long)pktnum,"Checksum error");
3070 return('Q');
3071 }
3072 break;
3073 case 3: /* Type 3, 16-bit CRC */
3074 crc = (xunchar(pbc[0]) << 12)
3075 | (xunchar(pbc[1]) << 6)
3076 | (xunchar(pbc[2]));
3077 if (crc != chk3(recpkt+lp,j-lp)) {
3078 if (type == 'E') { /* Allow E packets to have type 1 */
3079 recpkt[j++] = pbc[0];
3080 recpkt[j++] = pbc[1];
3081 recpkt[j] = '\0';
3082 if (xunchar(pbc[2]) == chk1(recpkt+lp,j-lp))
3083 break;
3084 else { j -=2; recpkt[j] = '\0'; }
3085 }
3086 #ifdef DEBUG
3087 if (deblog) {
3088 debug(F110,"checked chars",recpkt+lp,0);
3089 debug(F101,"block check (3)","",crc);
3090 debug(F101,"should be (3)","",(int) chk3(recpkt+lp,j-lp));
3091 }
3092 #endif /* DEBUG */
3093 freerbuf(k);
3094 logpkt('r',-1,(CHAR *)"<crunched:chk3>",0);
3095 xxscreen(SCR_PT,'%',(long)pktnum,"CRC error");
3096 return('Q');
3097 }
3098 break;
3099 case 4: /* Type 4 = Type 2, no blanks. */
3100 x = (unsigned)((xunchar(*pbc) - 1) << 6) |
3101 (unsigned)(xunchar(pbc[1]) - 1);
3102 if (x != chk2(recpkt+lp,j-lp)) {
3103 if (type == 'E') { /* Allow E packets to have type 1 */
3104 recpkt[j++] = pbc[0];
3105 recpkt[j] = '\0';
3106 if (xunchar(pbc[1]) == chk1(recpkt+lp,j-lp))
3107 break;
3108 else
3109 recpkt[--j] = '\0';
3110 }
3111 debug(F101,"bad type B block check","",x);
3112 freerbuf(k);
3113 logpkt('r',-1,(CHAR *)"<crunched:chkb>",0);
3114 xxscreen(SCR_PT,'%',(long)pktnum,"Checksum error");
3115 return('Q');
3116 }
3117 break;
3118 default: /* Shouldn't happen... */
3119 freerbuf(k);
3120 logpkt('r',-1,(CHAR *)"<crunched:chkx>",0);
3121 xxscreen(SCR_PT,'%',(long)pktnum,"(crunched)");
3122 return('Q');
3123 }
3124 debug(F101,"rpack block check OK","",rsn);
3125
3126 /* Now we can believe the sequence number, and other fields. */
3127 /* Here we violate strict principles of layering, etc, and look at the */
3128 /* packet sequence number. If there's already a packet with the same */
3129 /* number in the window, we remove this one so that the window will not */
3130 /* fill up. */
3131
3132 if ((x = rseqtbl[rsn]) != -1) { /* Already a packet with this number */
3133 retrans++; /* Count it for statistics */
3134 debug(F101,"rpack got dup","",rsn);
3135 logpkt('r',rsn,(CHAR *)"<duplicate>",0);
3136 freerbuf(x); /* Free old buffer, keep new packet. */
3137 r_pkt[k].pk_rtr++; /* Count this as a retransmission. */
3138 }
3139
3140 /* New packet, not seen before, enter it into the receive window. */
3141
3142 #ifdef CK_TIMERS
3143 if (timint > 0)
3144 rrttbl[rsn] = gtimer(); /* Timestamp */
3145 #endif /* CK_TIMERS */
3146
3147 rseqtbl[rsn] = k; /* Make back pointer */
3148 r_pkt[k].pk_seq = rsn; /* Record in packet info structure */
3149 r_pkt[k].pk_typ = type; /* Sequence, type,... */
3150 r_pkt[k].pk_adr = rdatap; /* pointer to data buffer */
3151 if (local) { /* Save a function call! */
3152 int x = 0;
3153 if (fdispla != XYFD_N) x = 1;
3154 if (fdispla == XYFD_B && (type == 'D' || sndtyp == 'D')) x = 0;
3155 if (x) /* Update screen */
3156 xxscreen(SCR_PT,(char)type,(long)rsn,(char *)sohp);
3157 }
3158 return(type); /* Return packet type */
3159 }
3160
3161 /* L O G P K T -- Log packet number n, pointed to by s. */
3162
3163 /* c = 's' (send) or 'r' (receive) */
3164
3165 VOID
3166 #ifdef CK_ANSIC
logpkt(char c,int n,CHAR * s,int len)3167 logpkt(char c,int n, CHAR *s, int len)
3168 #else
3169 logpkt(c,n,s,len) char c; int n; CHAR *s; int len;
3170 #endif /* CK_ANSIC */
3171 /* logpkt */ {
3172 char plog[20];
3173 if (!s) s = (CHAR *)"";
3174 if (pktlog) if (chkfn(ZPFILE) > 0) {
3175 if (n < 0) /* Construct entry header */
3176 sprintf(plog,"%c-xx-%02d-",c,(gtimer()%60)); /* safe */
3177 else
3178 sprintf(plog,"%c-%02d-%02d-",c,n,(gtimer()%60)); /* safe */
3179 if (zsoutx(ZPFILE,plog,(int)strlen(plog)) < 0) {
3180 pktlog = 0;
3181 return;
3182 } else {
3183 if (len == 0)
3184 len = strlen((char *)s);
3185 if (len > 0) {
3186 char * p; /* Make SOP printable */
3187 int x; /* so we can look at logs without */
3188 p = dbchr(*s); /* triggering autodownload. */
3189 x = strlen(dbchr(*s));
3190 if (*s < 32 || (*s > 127 && *s < 160)) {
3191 if (zsoutx(ZPFILE,p,x) < 0) {
3192 pktlog = 0;
3193 return;
3194 } else {
3195 len--;
3196 s++;
3197 }
3198 }
3199 }
3200 if (zsoutx(ZPFILE,(char *)s,len) < 0) {
3201 pktlog = 0;
3202 return;
3203 } else if (zsoutx(ZPFILE,
3204 #ifdef UNIX
3205 "\n", 1
3206 #else
3207 #ifdef datageneral
3208 "\n", 1
3209 #else
3210 #ifdef OSK
3211 "\r", 1
3212 #else
3213 #ifdef MAC
3214 "\r", 1
3215 #else
3216 "\015\012", 2
3217 #endif /* MAC */
3218 #endif /* OSK */
3219 #endif /* datageneral */
3220 #endif /* UNIX */
3221 ) < 0) {
3222 pktlog = 0;
3223 }
3224 }
3225 }
3226 }
3227
3228 /* T S T A T S -- Record statistics in transaction log */
3229
3230 VOID
tstats()3231 tstats() {
3232 char *tp = NULL;
3233 #ifdef GFTIMER
3234 CKFLOAT xx; /* Elapsed time divisor */
3235 #endif /* GFTIMER */
3236
3237 debug(F101,"tstats xfsecs","",xfsecs);
3238 debug(F101,"tstats filcnt","",filcnt);
3239 if (filcnt == 1) { /* Get timing for statistics */
3240 tsecs = xfsecs; /* Single file, we already have it */
3241 #ifdef GFTIMER
3242 debug(F101,"tstats fpxfsecs","",(int)fpxfsecs);
3243 fptsecs = fpxfsecs;
3244 #endif /* GFTIMER */
3245 } else { /* Multiple files */
3246 tsecs = gtimer(); /* Get current time */
3247 #ifdef GFTIMER
3248 fptsecs = gftimer();
3249 #endif /* GFTIMER */
3250 }
3251 #ifdef GFTIMER
3252 if (fptsecs <= GFMINTIME) /* Calculate CPS */
3253 fptsecs = (CKFLOAT) GFMINTIME;
3254 debug(F101,"tstats fptsecs","",(int)fptsecs);
3255 xx = (CKFLOAT) tfc / fptsecs;
3256 if (sizeof(long) <= 4) { /* doesn't account for 16-bit longs */
3257 if (xx > 2147483647.0)
3258 tfcps = 2147483647L; /* 31 bits */
3259 else
3260 tfcps = (long) xx;
3261 } else
3262 tfcps = (long) xx;
3263 #else
3264 if (tsecs < 2L)
3265 tsecs = 1L;
3266 debug(F101,"tstats tsecs","",tsecs);
3267 tfcps = tfc / tsecs;
3268 #endif /* GFTIMER */
3269
3270 ztime(&tp); /* Get time stamp */
3271 tlog(F100,"","",0L); /* Leave a blank line */
3272 tlog(F110,"Transaction complete",tp,0L); /* Record it */
3273
3274 if (filcnt < 1) return; /* If no files, done. */
3275
3276 /* If multiple files, record character totals for all files */
3277
3278 if (filcnt > 1) {
3279 tlog(F101," files transferred ","",filcnt - filrej);
3280 tlog(F101," total file characters ","",tfc);
3281 tlog(F101," communication line in ","",tlci);
3282 tlog(F101," communication line out ","",tlco);
3283 }
3284
3285 /* Record timing info for one or more files */
3286
3287 #ifdef GFTIMER
3288 if (filcnt - filrej == 1) {
3289 tlog(F101," elapsed time (seconds) ","",(long) fpxfsecs);
3290 tlog(F101," effective data rate ","",filcps);
3291 } else {
3292 tlog(F101," elapsed time (seconds) ","",(long) fptsecs);
3293 tlog(F101," effective data rate ","",(long) xx);
3294 }
3295 #else
3296 tlog(F101," elapsed time (seconds) ","",tsecs);
3297 if (tsecs > 0)
3298 tlog(F101," effective data rate ","",(tfc / tsecs));
3299 #endif /* GFTIMER */
3300
3301 tlog(F100,"","",0L); /* Leave a blank line */
3302 }
3303
3304 /* F S T A T S -- Record file statistics in transaction log */
3305
3306 VOID
fcps()3307 fcps() {
3308 #ifdef GFTIMER
3309 double xx;
3310 fpxfsecs = gftimer() - fpfsecs;
3311 if (fpxfsecs <= GFMINTIME)
3312 fpxfsecs = (CKFLOAT) GFMINTIME;
3313 xx = (CKFLOAT) ffc / fpxfsecs;
3314 if (sizeof(long) <= 4) {
3315 if (xx > 2147483647.0)
3316 tfcps = 2147483647L; /* 31 bits */
3317 else
3318 filcps = (long) xx;
3319 } else
3320 filcps = (long) xx;
3321 if (sizeof(int) >= 4)
3322 xfsecs = (int) fpxfsecs;
3323 else if (fpxfsecs < 32768.0)
3324 xfsecs = (int) fpxfsecs;
3325 else
3326 xfsecs = 32767;
3327 #else /* GFTIMER */
3328 xfsecs = gtimer() - fsecs;
3329 if (xfsecs < 1L) xfsecs = 1L;
3330 filcps = ffc / xfsecs;
3331 #endif /* GFTIMER */
3332 }
3333
3334 VOID
fstats()3335 fstats() {
3336 tfc += ffc;
3337 #ifdef DEBUG
3338 if (deblog) {
3339 debug(F101,"fstats tfc","",tfc);
3340 debug(F101,"fstats what","",what);
3341 debug(F110,"fstats epktmsg",epktmsg,0);
3342 }
3343 #endif /* DEBUG */
3344 #ifdef TLOG
3345 if (!discard && !cxseen && !czseen && what != W_NOTHING && !*epktmsg)
3346 tlog(F101," complete, size","",ffc);
3347 #endif /* TLOG */
3348 }
3349
3350 #endif /* NOXFER */
3351