1 | #define NEWDPL |
---|
2 | |
---|
3 | /* C K C F N 2 -- System-independent Kermit protocol support functions... */ |
---|
4 | |
---|
5 | /* ...Part 2 (continued from ckcfns.c) */ |
---|
6 | |
---|
7 | /* |
---|
8 | Author: Frank da Cruz <fdc@columbia.edu>, |
---|
9 | Columbia University Academic Information Systems, New York City. |
---|
10 | |
---|
11 | Copyright (C) 1985, 1996, Trustees of Columbia University in the City of New |
---|
12 | York. The C-Kermit software may not be, in whole or in part, licensed or |
---|
13 | sold for profit as a software product itself, nor may it be included in or |
---|
14 | distributed with commercial products or otherwise distributed by commercial |
---|
15 | concerns to their clients or customers without written permission of the |
---|
16 | Office of Kermit Development and Distribution, Columbia University. This |
---|
17 | copyright notice must not be removed, altered, or obscured. |
---|
18 | */ |
---|
19 | /* |
---|
20 | Note -- if you change this file, please amend the version number and date at |
---|
21 | the top of ckcfns.c accordingly. |
---|
22 | */ |
---|
23 | |
---|
24 | #include "ckcsym.h" /* Compilation options */ |
---|
25 | #include "ckcdeb.h" /* Debugging and other symbols */ |
---|
26 | #include "ckcasc.h" /* ASCII symbols */ |
---|
27 | #include "ckcker.h" /* Kermit symbols */ |
---|
28 | #include "ckcxla.h" /* Translation */ |
---|
29 | |
---|
30 | #ifdef TCPSOCKET /* For TELNET business in spack() */ |
---|
31 | #ifndef NP_TELNET /* Avoid dragging in ckcnet.h */ |
---|
32 | #define NP_TELNET 1 |
---|
33 | #define TNL_CR 0 /* CR sends bare carriage return */ |
---|
34 | #define TNL_CRNUL 1 /* CR and NUL */ |
---|
35 | #define TNL_CRLF 2 /* CR and LF */ |
---|
36 | #define TNL_LF 3 /* LF instead of CR */ |
---|
37 | #endif /* NP_TELNET */ |
---|
38 | extern int tn_nlm, ttnproto; |
---|
39 | extern int me_binary, tn_b_nlm; |
---|
40 | #endif /* TCPSOCKET */ |
---|
41 | |
---|
42 | #ifdef DYNAMIC |
---|
43 | extern struct pktinfo *s_pkt; /* array of pktinfo structures */ |
---|
44 | extern struct pktinfo *r_pkt; /* array of pktinfo structures */ |
---|
45 | #else |
---|
46 | extern struct pktinfo s_pkt[]; /* array of pktinfo structures */ |
---|
47 | extern struct pktinfo r_pkt[]; /* array of pktinfo structures */ |
---|
48 | #endif /* DYNAMIC */ |
---|
49 | |
---|
50 | extern int sseqtbl[], rseqtbl[], sbufuse[], sacktbl[], wslots, winlo, |
---|
51 | sbufnum, rbufnum, pktpaus; |
---|
52 | |
---|
53 | extern int ttprty; /* from ck*tio.c */ |
---|
54 | extern int autopar; |
---|
55 | |
---|
56 | extern int spsiz, spmax, rpsiz, timint, timef, npad, bestlen, maxsend; |
---|
57 | extern int rpt, rptq, rptflg, capas, spsizf, en_fin, tsecs, network, flow; |
---|
58 | extern int pktnum, sndtyp, rcvtyp, bctr, bctu, bctl, rsn, rln, maxtry, size; |
---|
59 | extern int osize, maxsize, spktl, rpktl, nfils, stdouf, warn, parity; |
---|
60 | extern int turn, turnch, delay, displa, pktlog, tralog, seslog, xflg, mypadn; |
---|
61 | extern int hcflg, local, server, cxseen, czseen, discard, slostart; |
---|
62 | extern int nakstate, quiet, success, xitsta, what; |
---|
63 | extern int spackets, rpackets, timeouts, retrans, crunched, urpsiz; |
---|
64 | |
---|
65 | extern long filcnt, filrej, ffc, flci, flco, tlci, tlco, tfc, speed; |
---|
66 | |
---|
67 | extern char *cmarg, filnam[], *hlptxt; |
---|
68 | |
---|
69 | extern CHAR padch, mypadc, eol, seol, ctlq, sstate; |
---|
70 | extern CHAR *recpkt, *data, myinit[]; |
---|
71 | extern CHAR *srvptr, stchr, mystch, *rdatap; |
---|
72 | extern CHAR padbuf[]; |
---|
73 | #ifdef pdp11 |
---|
74 | extern CHAR srvcmd[]; |
---|
75 | extern CHAR *pktmsg; |
---|
76 | #else |
---|
77 | #ifdef DYNAMIC |
---|
78 | extern CHAR *srvcmd; |
---|
79 | extern CHAR *pktmsg; |
---|
80 | #else |
---|
81 | extern CHAR srvcmd[]; |
---|
82 | extern CHAR pktmsg[]; |
---|
83 | #endif /* DYNAMIC */ |
---|
84 | #endif /* pdp11 */ |
---|
85 | |
---|
86 | int numerrs = 0; /* Number of packet errors so far */ |
---|
87 | int rcvtimo = 0; /* Timeout for receiving a packet */ |
---|
88 | |
---|
89 | #ifdef CK_TIMERS |
---|
90 | int rrttbl[64], srttbl[64]; /* Packet timestamp tables */ |
---|
91 | extern int rttflg; |
---|
92 | #define RTT_SCALE 1000 |
---|
93 | long |
---|
94 | rttsamples, /* Round trip time samples */ |
---|
95 | rttdelay, /* RTT delay */ |
---|
96 | pktintvl, /* Interpacket arrival time */ |
---|
97 | rttvariance, /* RTT variance */ |
---|
98 | rttstddev; /* RTT standard deviation */ |
---|
99 | #endif /* CK_TIMERS */ |
---|
100 | |
---|
101 | static CHAR p_tbl[] = { /* Even parity table for dopar(). */ |
---|
102 | (CHAR) '\000', /* ANSI C casts '\ooo' constants */ |
---|
103 | (CHAR) '\201', /* to signed char, so we have to */ |
---|
104 | (CHAR) '\202', /* cast back to unsigned char... */ |
---|
105 | (CHAR) '\003', |
---|
106 | (CHAR) '\204', |
---|
107 | (CHAR) '\005', |
---|
108 | (CHAR) '\006', |
---|
109 | (CHAR) '\207', |
---|
110 | (CHAR) '\210', |
---|
111 | (CHAR) '\011', |
---|
112 | (CHAR) '\012', |
---|
113 | (CHAR) '\213', |
---|
114 | (CHAR) '\014', |
---|
115 | (CHAR) '\215', |
---|
116 | (CHAR) '\216', |
---|
117 | (CHAR) '\017', |
---|
118 | (CHAR) '\220', |
---|
119 | (CHAR) '\021', |
---|
120 | (CHAR) '\022', |
---|
121 | (CHAR) '\223', |
---|
122 | (CHAR) '\024', |
---|
123 | (CHAR) '\225', |
---|
124 | (CHAR) '\226', |
---|
125 | (CHAR) '\027', |
---|
126 | (CHAR) '\030', |
---|
127 | (CHAR) '\231', |
---|
128 | (CHAR) '\232', |
---|
129 | (CHAR) '\033', |
---|
130 | (CHAR) '\234', |
---|
131 | (CHAR) '\035', |
---|
132 | (CHAR) '\036', |
---|
133 | (CHAR) '\237', |
---|
134 | (CHAR) '\240', |
---|
135 | (CHAR) '\041', |
---|
136 | (CHAR) '\042', |
---|
137 | (CHAR) '\243', |
---|
138 | (CHAR) '\044', |
---|
139 | (CHAR) '\245', |
---|
140 | (CHAR) '\246', |
---|
141 | (CHAR) '\047', |
---|
142 | (CHAR) '\050', |
---|
143 | (CHAR) '\251', |
---|
144 | (CHAR) '\252', |
---|
145 | (CHAR) '\053', |
---|
146 | (CHAR) '\254', |
---|
147 | (CHAR) '\055', |
---|
148 | (CHAR) '\056', |
---|
149 | (CHAR) '\257', |
---|
150 | (CHAR) '\060', |
---|
151 | (CHAR) '\261', |
---|
152 | (CHAR) '\262', |
---|
153 | (CHAR) '\063', |
---|
154 | (CHAR) '\264', |
---|
155 | (CHAR) '\065', |
---|
156 | (CHAR) '\066', |
---|
157 | (CHAR) '\267', |
---|
158 | (CHAR) '\270', |
---|
159 | (CHAR) '\071', |
---|
160 | (CHAR) '\072', |
---|
161 | (CHAR) '\273', |
---|
162 | (CHAR) '\074', |
---|
163 | (CHAR) '\275', |
---|
164 | (CHAR) '\276', |
---|
165 | (CHAR) '\077', |
---|
166 | (CHAR) '\300', |
---|
167 | (CHAR) '\101', |
---|
168 | (CHAR) '\102', |
---|
169 | (CHAR) '\303', |
---|
170 | (CHAR) '\104', |
---|
171 | (CHAR) '\305', |
---|
172 | (CHAR) '\306', |
---|
173 | (CHAR) '\107', |
---|
174 | (CHAR) '\110', |
---|
175 | (CHAR) '\311', |
---|
176 | (CHAR) '\312', |
---|
177 | (CHAR) '\113', |
---|
178 | (CHAR) '\314', |
---|
179 | (CHAR) '\115', |
---|
180 | (CHAR) '\116', |
---|
181 | (CHAR) '\317', |
---|
182 | (CHAR) '\120', |
---|
183 | (CHAR) '\321', |
---|
184 | (CHAR) '\322', |
---|
185 | (CHAR) '\123', |
---|
186 | (CHAR) '\324', |
---|
187 | (CHAR) '\125', |
---|
188 | (CHAR) '\126', |
---|
189 | (CHAR) '\327', |
---|
190 | (CHAR) '\330', |
---|
191 | (CHAR) '\131', |
---|
192 | (CHAR) '\132', |
---|
193 | (CHAR) '\333', |
---|
194 | (CHAR) '\134', |
---|
195 | (CHAR) '\335', |
---|
196 | (CHAR) '\336', |
---|
197 | (CHAR) '\137', |
---|
198 | (CHAR) '\140', |
---|
199 | (CHAR) '\341', |
---|
200 | (CHAR) '\342', |
---|
201 | (CHAR) '\143', |
---|
202 | (CHAR) '\344', |
---|
203 | (CHAR) '\145', |
---|
204 | (CHAR) '\146', |
---|
205 | (CHAR) '\347', |
---|
206 | (CHAR) '\350', |
---|
207 | (CHAR) '\151', |
---|
208 | (CHAR) '\152', |
---|
209 | (CHAR) '\353', |
---|
210 | (CHAR) '\154', |
---|
211 | (CHAR) '\355', |
---|
212 | (CHAR) '\356', |
---|
213 | (CHAR) '\157', |
---|
214 | (CHAR) '\360', |
---|
215 | (CHAR) '\161', |
---|
216 | (CHAR) '\162', |
---|
217 | (CHAR) '\363', |
---|
218 | (CHAR) '\164', |
---|
219 | (CHAR) '\365', |
---|
220 | (CHAR) '\366', |
---|
221 | (CHAR) '\167', |
---|
222 | (CHAR) '\170', |
---|
223 | (CHAR) '\371', |
---|
224 | (CHAR) '\372', |
---|
225 | (CHAR) '\173', |
---|
226 | (CHAR) '\374', |
---|
227 | (CHAR) '\175', |
---|
228 | (CHAR) '\176', |
---|
229 | (CHAR) '\377' |
---|
230 | }; |
---|
231 | |
---|
232 | /* CRC generation tables */ |
---|
233 | |
---|
234 | long crcta[16] = { 0L, 010201L, 020402L, 030603L, 041004L, |
---|
235 | 051205L, 061406L, 071607L, 0102010L, 0112211L, 0122412L, 0132613L, 0143014L, |
---|
236 | 0153215L, 0163416L, 0173617L |
---|
237 | }; |
---|
238 | |
---|
239 | long crctb[16] = { 0L, 010611L, 021422L, 031233L, 043044L, |
---|
240 | 053655L, 062466L, 072277L, 0106110L, 0116701L, 0127532L, 0137323L, 0145154L, |
---|
241 | 0155745L, 0164576L, 0174367L |
---|
242 | }; |
---|
243 | |
---|
244 | #ifdef CK_TIMERS |
---|
245 | /* |
---|
246 | Round-trip timer calculations adapted from Tim Kientzle's article, |
---|
247 | "Improving Kermit Performance", Dr Dobb's Journal, February 1996. |
---|
248 | */ |
---|
249 | |
---|
250 | /* R T T I N I T -- Initialize timers at start of transaction */ |
---|
251 | |
---|
252 | VOID |
---|
253 | rttinit() { /* Initialize round-trip timing */ |
---|
254 | int i; |
---|
255 | |
---|
256 | rttsamples = 0L; /* Samples (packets) */ |
---|
257 | rttvariance = 0L; /* Variance in delay */ |
---|
258 | rttdelay = (long) timint * RTT_SCALE; /* Delay */ |
---|
259 | pktintvl = (long) timint * RTT_SCALE; /* Delay */ |
---|
260 | rttstddev = (long) timint * RTT_SCALE; /* Standard deviation of delay */ |
---|
261 | |
---|
262 | /* Tables of timestamps indexed by packet sequence number */ |
---|
263 | |
---|
264 | for (i = 0; i < 64; i++) { |
---|
265 | rrttbl[i] = -1; /* Time each packet was received */ |
---|
266 | srttbl[i] = -1; /* Time each packet was sent */ |
---|
267 | } |
---|
268 | rcvtimo = timint; /* Initial timeout is what user said */ |
---|
269 | } |
---|
270 | |
---|
271 | /* G E T R T T -- Get packet round trip time */ |
---|
272 | /* |
---|
273 | Call with nakstate == 0 if file sender, nonzero if receiver, |
---|
274 | and n == packet sequence number of the packet we just received. |
---|
275 | |
---|
276 | Returns: |
---|
277 | -1 on failure with rcvtimo set to timint (what the user said), or: |
---|
278 | 0 on success with rcvtimo set to dynamically calculated value: |
---|
279 | 1 <= rcvtimo <= timint * 3. |
---|
280 | */ |
---|
281 | int |
---|
282 | getrtt(nakstate, n) int nakstate, n; { |
---|
283 | long rttdiff; |
---|
284 | extern int mintime, maxtime; |
---|
285 | |
---|
286 | int x, y, yy, z = 0, zz = 0; /* How long did it take to get here? */ |
---|
287 | |
---|
288 | rcvtimo = timint; /* Default timeout is what user said */ |
---|
289 | |
---|
290 | if (timint == 0) /* We're not timing out. */ |
---|
291 | return(0); |
---|
292 | |
---|
293 | if (!rttflg) /* Not supposed to be doing this? */ |
---|
294 | return(-1); /* So don't */ |
---|
295 | |
---|
296 | if (!RTT_SCALE) /* Paranoia... */ |
---|
297 | return(-1); |
---|
298 | |
---|
299 | /* rtimer() (reset timer) is not called until 1st data packet */ |
---|
300 | /* S (F [ A ] D* Z)* B */ |
---|
301 | |
---|
302 | /* NOTE: we calculate both the round-trip time AND the packet */ |
---|
303 | /* arrival rate. We don't use the RTT for anything, we just display it. */ |
---|
304 | /* Timeouts are based on the packet arrival rate. */ |
---|
305 | |
---|
306 | if (spackets > 3) { /* Don't start till 4th packet */ |
---|
307 | if (nakstate) { /* File receiver */ |
---|
308 | x = rrttbl[n]; /* Time when I got packet n */ |
---|
309 | y = rrttbl[n > 0 ? n - 1 : 63]; /* Time when I got packet n-1 */ |
---|
310 | yy = srttbl[n > 0 ? n - 1 : 63]; /* Time when I sent ACK(n-1) */ |
---|
311 | if (x > -1 && y > -1) { /* Be careful */ |
---|
312 | z = x - y; /* Packet rate */ |
---|
313 | zz = x - yy; /* Round trip time */ |
---|
314 | debug(F101,"RTT RECV","",z); |
---|
315 | } else { /* This shouldn't happen */ |
---|
316 | debug(F101,"RTT RECV ERROR spackets","",spackets); |
---|
317 | debug(F101,"RTT RECV ERROR sequence","",n); |
---|
318 | return(-1); |
---|
319 | } |
---|
320 | } else { /* File sender */ |
---|
321 | x = rrttbl[n]; /* Time when I got ACK(n) */ |
---|
322 | y = rrttbl[n > 0 ? n - 1 : 63]; /* Time when I got packet n-1 */ |
---|
323 | yy = srttbl[n]; /* Time when I sent n */ |
---|
324 | if (x > -1 && y > -1) { |
---|
325 | z = x - y; /* Packet rate */ |
---|
326 | zz = x - yy; /* Round trip time */ |
---|
327 | debug(F101,"RTT SEND","",z); |
---|
328 | } else { |
---|
329 | debug(F100,"RTT SEND ERROR","",0); |
---|
330 | return(-1); |
---|
331 | } |
---|
332 | } |
---|
333 | if (z < 1) /* For fast connections */ |
---|
334 | z = RTT_SCALE / 2; /* Convert to scale... */ |
---|
335 | else |
---|
336 | z *= RTT_SCALE; |
---|
337 | |
---|
338 | if (zz < 1) /* For fast connections */ |
---|
339 | zz = RTT_SCALE / 2; /* Convert to scale... */ |
---|
340 | else |
---|
341 | zz *= RTT_SCALE; |
---|
342 | |
---|
343 | rttdelay = zz; /* Round trip time of this packet */ |
---|
344 | if (rttsamples++ == 0L) { /* First sample */ |
---|
345 | pktintvl = z; |
---|
346 | rttdiff = 0; |
---|
347 | } else { /* Subsequent samples */ |
---|
348 | long oldavg = pktintvl; |
---|
349 | long rttdiffsq; |
---|
350 | |
---|
351 | if (rttsamples > 30) /* Use real average for first 30 */ |
---|
352 | rttsamples = 30; /* then decaying average. */ |
---|
353 | |
---|
354 | /* Average delay, difference squared, variance, std deviation */ |
---|
355 | |
---|
356 | pktintvl += (z - pktintvl) / rttsamples; |
---|
357 | rttdiffsq = (z - oldavg) * (z - oldavg); |
---|
358 | rttvariance += (rttdiffsq - rttvariance) / rttsamples; |
---|
359 | debug(F101,"RTT stddev1","",rttstddev); |
---|
360 | if (rttstddev < 1L) /* It can be zero, in which case */ |
---|
361 | rttstddev = RTT_SCALE / 3; /* set it to something small... */ |
---|
362 | rttstddev = (rttstddev + rttvariance / rttstddev) / 2; |
---|
363 | } |
---|
364 | debug(F101,"RTT stddev2","",rttstddev); |
---|
365 | debug(F101,"RTT delay ","",pktintvl); |
---|
366 | rcvtimo = (pktintvl + (3L * rttstddev)) / RTT_SCALE + 1; |
---|
367 | if (rpackets < 32) /* Allow for slow start */ |
---|
368 | rcvtimo += rcvtimo + 2; |
---|
369 | else if (rpackets < 64) |
---|
370 | rcvtimo += rcvtimo / 2 + 1; |
---|
371 | if (rcvtimo < mintime) /* Lower bound */ |
---|
372 | rcvtimo = mintime; |
---|
373 | if (maxtime > 0) { /* User specified an upper bound */ |
---|
374 | if (rcvtimo > maxtime) |
---|
375 | rcvtimo = maxtime; |
---|
376 | } else if (maxtime == 0) { /* User didn't specify */ |
---|
377 | if (rcvtimo > timint * 6) |
---|
378 | rcvtimo = timint * 6; |
---|
379 | } |
---|
380 | debug(F101,"RTT rcvtimo","",rcvtimo); |
---|
381 | } |
---|
382 | return(0); |
---|
383 | } |
---|
384 | #endif /* CK_TIMERS */ |
---|
385 | |
---|
386 | /* I N P U T -- Attempt to read packet number 'pktnum'. */ |
---|
387 | |
---|
388 | /* |
---|
389 | This is the function that feeds input to Kermit's finite state machine, |
---|
390 | in the form of a character in the range 32-126, normally a packet type |
---|
391 | (uppercase letter) or pseudo-packet-type (lowercase letter). |
---|
392 | |
---|
393 | If a special start state is in effect, that state is returned as if it were |
---|
394 | the type of an incoming packet. |
---|
395 | */ |
---|
396 | int |
---|
397 | input() { |
---|
398 | int type, acktype; /* Received packet type */ |
---|
399 | int x, y, k; /* Workers */ |
---|
400 | int z, pi, nf; /* Worker, packet index, NAK flag */ |
---|
401 | int nak2ack = 0; |
---|
402 | |
---|
403 | debug(F101,"input sstate","",sstate); |
---|
404 | debug(F101," nakstate","",nakstate); |
---|
405 | debug(F000," sndtyp","",sndtyp); |
---|
406 | |
---|
407 | while (1) { /* Big loop... */ |
---|
408 | |
---|
409 | if (sstate != 0) { /* If a start state is in effect, */ |
---|
410 | type = sstate; /* return it like a packet type, */ |
---|
411 | sstate = 0; /* and then nullify it. */ |
---|
412 | numerrs = 0; /* (PWP) no errors so far */ |
---|
413 | return(type); |
---|
414 | } |
---|
415 | |
---|
416 | if (nakstate) { /* This section for file receiver. */ |
---|
417 | |
---|
418 | if (wslots > 1) { /* If we're doing windows, */ |
---|
419 | x = rseqtbl[winlo]; /* see if desired packet already in. */ |
---|
420 | debug(F101," winlo","",winlo); |
---|
421 | debug(F101," rseqtbl[winlo]","",rseqtbl[winlo]); |
---|
422 | if (x > -1) { /* Already there? */ |
---|
423 | if (r_pkt[x].pk_seq == winlo) { /* (double check) */ |
---|
424 | rsn = winlo; /* Yes, return its info */ |
---|
425 | debug(F101,"input return pre-stashed packet","",rsn); |
---|
426 | dumprbuf(); |
---|
427 | rdatap = r_pkt[x].pk_adr; /* like rpack would do. */ |
---|
428 | rln = (int)strlen((char *) rdatap); |
---|
429 | type = r_pkt[x].pk_typ; |
---|
430 | break; |
---|
431 | } |
---|
432 | } |
---|
433 | } |
---|
434 | type = rpack(); /* Try to read a packet. */ |
---|
435 | debug(F111,"input recv",(char *) rdatap,(int) type); |
---|
436 | while (type == 'e') { /* Handle echoes */ |
---|
437 | debug(F000,"echo discarded","",type); |
---|
438 | type = rpack(); |
---|
439 | } |
---|
440 | #ifndef OLDCHKINT |
---|
441 | if (type == 'z') { |
---|
442 | errpkt((CHAR *)"User cancelled."); |
---|
443 | strcpy((char *)pktmsg,"User cancelled."); |
---|
444 | type = 'E'; |
---|
445 | break; |
---|
446 | } |
---|
447 | #endif /* OLDCHKINT */ |
---|
448 | if (type < -1) return('q'); /* Ctrl-C or connection lost */ |
---|
449 | if (type < 0) { /* Receive window full */ |
---|
450 | /* Another thing to do here would be to delete */ |
---|
451 | /* the highest packet and NAK winlo. But that */ |
---|
452 | /* shouldn't be necessary since the other Kermit */ |
---|
453 | /* should not have sent a packet outside the window. */ |
---|
454 | debug(F101,"rpack receive window full","",0); |
---|
455 | dumprbuf(); |
---|
456 | errpkt((CHAR *)"Receive window full."); |
---|
457 | strcpy((char *)pktmsg,"Receive window full."); |
---|
458 | type = 'E'; |
---|
459 | break; |
---|
460 | } |
---|
461 | dumprbuf(); |
---|
462 | |
---|
463 | #ifdef OLDCHKINT |
---|
464 | if (chkint() < 0) { /* Check for console interrupts. */ |
---|
465 | errpkt((CHAR *)"User cancelled."); |
---|
466 | strcpy((char *)pktmsg,"User cancelled."); |
---|
467 | type = 'E'; |
---|
468 | break; |
---|
469 | } |
---|
470 | #endif /* OLDCHKINT */ |
---|
471 | |
---|
472 | if (type == 'E') { |
---|
473 | debug(F101,"input got E, nakstate","",nakstate); |
---|
474 | break; /* Error packet */ |
---|
475 | } |
---|
476 | if (type == 'Q') { /* Crunched packet. */ |
---|
477 | crunched++; |
---|
478 | numerrs++; |
---|
479 | /* |
---|
480 | Packet arrived damaged. It was most likely the packet we were expecting |
---|
481 | next, so we send a NAK for that packet. Prior to 5A(189), we always |
---|
482 | NAK'd winlo here, but that was bad because if two (or more) different |
---|
483 | packets were damaged, we would keep NAKing the first one and never NAK the |
---|
484 | other ones, which could result in a lengthy series of timeouts. Now we |
---|
485 | NAK the oldest as-yet-unNAK'd missing packet. |
---|
486 | */ |
---|
487 | #ifdef CK_TIMERS |
---|
488 | rcvtimo++; /* Stretch the timeout a little */ |
---|
489 | #endif /* CK_TIMERS */ |
---|
490 | z = (winlo + wslots) % 64; /* Search from winlo to z */ |
---|
491 | debug(F101,"ZZZ crunched z","",z); |
---|
492 | nf = 0; /* NAK flag not set yet */ |
---|
493 | for (x = winlo; x != z; x = (x + 1) % 64) { |
---|
494 | debug(F101,"ZZZ x","",x); |
---|
495 | if (rseqtbl[x] > -1) /* Have I received packet x? */ |
---|
496 | continue; /* Yes, go on. */ |
---|
497 | debug(F101,"ZZZ x not recd yet","",x); |
---|
498 | pi = sseqtbl[x]; /* No, have I NAK'd it yet? */ |
---|
499 | if (pi < 0 || s_pkt[pi].pk_rtr == 0) { |
---|
500 | debug(F101,"ZZZ x not NAK'd yet","",x); |
---|
501 | nack(x); /* No, NAK it now. */ |
---|
502 | nf = 1; /* Flag that I did. */ |
---|
503 | break; |
---|
504 | } |
---|
505 | } |
---|
506 | if (!nf) { /* If we didn't NAK anything above, */ |
---|
507 | debug(F101,"ZZZ NAKing winlo","",winlo); |
---|
508 | if (nack(winlo) < 0) { /* we have to NAK winlo (again) */ |
---|
509 | errpkt((CHAR *)"Too many retries."); /* Too many */ |
---|
510 | strcpy((char *)pktmsg,"Timed out."); /* Give up */ |
---|
511 | type = 'E'; |
---|
512 | break; |
---|
513 | } |
---|
514 | } |
---|
515 | continue; |
---|
516 | } |
---|
517 | |
---|
518 | if (type == 'T') { /* Timeout */ |
---|
519 | #ifdef CK_TIMERS |
---|
520 | rcvtimo++; /* Stretch the timeout a little */ |
---|
521 | #endif /* CK_TIMERS */ |
---|
522 | timeouts++; |
---|
523 | debug(F101,"input receive-state timeout, winlo","",winlo); |
---|
524 | /* NAK only the packet at window-low */ |
---|
525 | debug(F101,"input sending NAK for winlo","",winlo); |
---|
526 | if (ttchk() > 0) /* Don't give up if there is still */ |
---|
527 | continue; /* something to read. */ |
---|
528 | if (nack(winlo) < 0) { |
---|
529 | debug(F101,"input sent too many naks","",winlo); |
---|
530 | errpkt((CHAR *)"Too many retries."); |
---|
531 | strcpy((char *)pktmsg,"Sent too many NAKs."); |
---|
532 | type = 'E'; |
---|
533 | break; |
---|
534 | } else continue; |
---|
535 | } |
---|
536 | |
---|
537 | if (rsn == winlo) { /* Got the packet we want, done. */ |
---|
538 | #ifdef CK_TIMERS |
---|
539 | if (rttflg) /* Dynamic round trip timers? */ |
---|
540 | getrtt(nakstate, rsn); /* yes, do it. */ |
---|
541 | #endif /* CK_TIMERS */ |
---|
542 | debug(F101,"input rsn=winlo","",rsn); |
---|
543 | break; |
---|
544 | } |
---|
545 | |
---|
546 | /* Got a packet out of order. */ |
---|
547 | |
---|
548 | debug(F101,"input recv got packet out of order","",rsn); |
---|
549 | k = rseqtbl[rsn]; /* Get window slot of this packet. */ |
---|
550 | debug(F101,"input recv rseqtbl[rsn]","",k); |
---|
551 | if (k < 0) { |
---|
552 | debug(F101,"input recv can't find index for rcvd pkt","",rsn); |
---|
553 | /* Was "Internal error 21" */ |
---|
554 | errpkt((CHAR *)"Sliding windows protocol error."); |
---|
555 | strcpy((char *)pktmsg,"Sliding windows protocol error."); |
---|
556 | type = 'E'; |
---|
557 | break; |
---|
558 | } |
---|
559 | y = chkwin(rsn,winlo,wslots); /* See what window it's in. */ |
---|
560 | debug(F101,"input recv chkwin","",y); |
---|
561 | if (y == 1) { /* From previous window. */ |
---|
562 | resend(rsn); /* Resend the ACK (might have data) */ |
---|
563 | freerpkt(rsn); /* Get rid of received packet */ |
---|
564 | continue; |
---|
565 | } else { /* In this window or out of range */ |
---|
566 | if (y < 0) /* If out of range entirely, */ |
---|
567 | freerpkt(rsn); /* release its buffer */ |
---|
568 | |
---|
569 | #ifdef COMMENT /* Ignore this and read what comes afterwards... */ |
---|
570 | /* |
---|
571 | We have received a packet, but not the one we want. It would seem to |
---|
572 | make sense to always send a NAK for the most desired packet (winlo). But |
---|
573 | consider this scenario: a packet arrived damaged so we NAK'd it above; |
---|
574 | then packets winlo+1, winlo+2, ... winlo+n arrive, each one making us |
---|
575 | send another NAK for winlo, so the other Kermit gets n NAKs for winlo, and |
---|
576 | either would have to resend it n times, or if n > retry limit, give up |
---|
577 | because of too many retries. So we compromise: If a packet arrives |
---|
578 | that is not the most desired packet (winlo), we NAK winlo, BUT ONLY IF |
---|
579 | it has not been NAK'd before. |
---|
580 | */ |
---|
581 | x = sseqtbl[winlo]; /* Get index of most desired packet */ |
---|
582 | if (s_pkt[x].pk_rtr == 0 || /* Not NAK'd before? */ |
---|
583 | rbufnum < 1) { /* Or receive window full? */ |
---|
584 | if (nack(winlo) < 0) { /* One or both, so NAK it now. */ |
---|
585 | errpkt((CHAR *)"Too many retries."); /* Too many */ |
---|
586 | strcpy((char *)pktmsg,"Timed out."); /* Give up */ |
---|
587 | type = 'E'; |
---|
588 | break; |
---|
589 | } else continue; |
---|
590 | } else continue; |
---|
591 | #endif /* COMMENT */ |
---|
592 | |
---|
593 | /* |
---|
594 | In version 5A(189), the strategy was revised to send NAKs for the oldest |
---|
595 | missing packet that had not been NAK'd before, which requires a search. |
---|
596 | Thus, if winlo was already NAK'd, instead of doing nothing, we send a NAK |
---|
597 | for the "lowest" as-yet-unNAK'd missing packet. |
---|
598 | |
---|
599 | If our receive window is full, however, we have no choice but to NAK winlo: |
---|
600 | */ |
---|
601 | debug(F101,"XXX checking rbufnum","",rbufnum); |
---|
602 | if (rbufnum < 1) { /* Receive window full? */ |
---|
603 | debug(F101,"XXX out of buffers","",rbufnum); /* Yes */ |
---|
604 | if (nack(winlo) < 0) { /* No choice, must NAK winlo. */ |
---|
605 | errpkt((CHAR *)"Too many retries."); /* Too many */ |
---|
606 | strcpy((char *)pktmsg,"Timed out."); /* Give up */ |
---|
607 | type = 'E'; |
---|
608 | break; |
---|
609 | } else continue; |
---|
610 | } |
---|
611 | /* |
---|
612 | Receive window not full. This is a packet in the current window but it is |
---|
613 | not the desired packet at winlo. So therefore there are gaps before this |
---|
614 | packet. So we find the "lowest" unNAK'd missing packet, if any, between |
---|
615 | winlo and this one, and NAK it. If there are no as-yet-unNAK'd missing |
---|
616 | packets in the window, then we send nothing and go wait for another packet. |
---|
617 | In theory, this could result in a timeout, but in practice it is likely that |
---|
618 | the already-NAK'd missing packets are already on their way. Note, we do not |
---|
619 | NAK ahead of ourselves, as that only creates unnecessary retransmissions. |
---|
620 | */ |
---|
621 | debug(F101,"XXX winlo","",winlo); |
---|
622 | for (x = winlo; x != rsn; x = (x + 1) % 64) { |
---|
623 | debug(F101,"XXX x","",x); |
---|
624 | if (rseqtbl[x] > -1) /* Have I received packet x? */ |
---|
625 | continue; /* Yes, check next sequence number. */ |
---|
626 | debug(F101,"XXX missing pkt","",x); |
---|
627 | pi = sseqtbl[x]; /* No, have I NAK'd it yet? */ |
---|
628 | if (pi < 0 || s_pkt[pi].pk_rtr == 0) { |
---|
629 | nack(x); /* No, NAK it now. */ |
---|
630 | debug(F101,"XXX nak","",x); |
---|
631 | break; |
---|
632 | } |
---|
633 | } |
---|
634 | } |
---|
635 | /*!!!*/ |
---|
636 | } else { /* Otherwise file sender... */ |
---|
637 | |
---|
638 | if (!nak2ack) { /* NAK(n+1) = ACK(n) */ |
---|
639 | |
---|
640 | if (wslots > 1) { /* Packet at winlo already ACK'd? */ |
---|
641 | if (sacktbl[winlo]) { /* If so, */ |
---|
642 | sacktbl[winlo] = 0; /* Turn off the ACK'd flag */ |
---|
643 | winlo = (winlo + 1) % 64; /* Rotate the window */ |
---|
644 | type = 'Y'; /* And return ACK */ |
---|
645 | debug(F101, |
---|
646 | "input send returning pre-stashed ACK","", |
---|
647 | winlo-1); |
---|
648 | break; |
---|
649 | } |
---|
650 | } |
---|
651 | type = rpack(); /* Try to read an acknowledgement */ |
---|
652 | debug(F111,"input send",(char *) rdatap,(int) type); |
---|
653 | while (type == 'e') { /* Handle echoes */ |
---|
654 | debug(F000,"echo discarded","",type); |
---|
655 | type = rpack(); |
---|
656 | } |
---|
657 | #ifndef OLDCHKINT |
---|
658 | if (type == 'z') { |
---|
659 | errpkt((CHAR *)"User cancelled."); |
---|
660 | strcpy((char *)pktmsg,"User cancelled."); |
---|
661 | type = 'E'; |
---|
662 | break; |
---|
663 | } |
---|
664 | #endif /* OLDCHKINT */ |
---|
665 | if (type == -2) return('q'); |
---|
666 | if (type == -1) { |
---|
667 | errpkt((CHAR *)"Receive window full"); /* was "internal */ |
---|
668 | debug(F101," wslots","",wslots); /* error 18" */ |
---|
669 | debug(F101," winlo","",winlo); |
---|
670 | debug(F101," pktnum","",pktnum); |
---|
671 | dumprbuf(); |
---|
672 | strcpy((char *)pktmsg,"Can't allocate receive buffer"); |
---|
673 | type = 'E'; |
---|
674 | break; |
---|
675 | } |
---|
676 | dumprbuf(); /* Debugging */ |
---|
677 | |
---|
678 | #ifdef OLDCHKINT |
---|
679 | if (chkint() < 0) { /* Check for console interrupts. */ |
---|
680 | errpkt((CHAR *)"User cancelled."); |
---|
681 | strcpy((char *)pktmsg,"User cancelled."); |
---|
682 | return(type = 'E'); |
---|
683 | } |
---|
684 | #endif /* OLDCHKINT */ |
---|
685 | |
---|
686 | /* Got a packet */ |
---|
687 | |
---|
688 | if (type == 'E') { |
---|
689 | debug(F101,"input send got E, nakstate","",nakstate); |
---|
690 | break; /* Error packet */ |
---|
691 | } |
---|
692 | if (type == 'Q') { /* Crunched packet */ |
---|
693 | crunched++; /* For statistics */ |
---|
694 | numerrs++; /* For packet resizing */ |
---|
695 | x = resend(winlo); /* Resend window-low */ |
---|
696 | if (x < 0) { |
---|
697 | type = 'E'; |
---|
698 | errpkt(pktmsg); |
---|
699 | break; |
---|
700 | } |
---|
701 | continue; |
---|
702 | } |
---|
703 | if (type == 'T') { /* Timeout waiting for ACKs. */ |
---|
704 | timeouts++; /* Count it */ |
---|
705 | numerrs++; /* Count an error too */ |
---|
706 | debug(F101,"input send state timeout, winlo","",winlo); |
---|
707 | |
---|
708 | /* Retransmit the oldest un-ACK'd packet. */ |
---|
709 | |
---|
710 | debug(F101,"input send resending winlo","",winlo); |
---|
711 | if (resend(winlo) < 0) { /* Check retries */ |
---|
712 | debug(F101,"input send too many resends","",maxtry); |
---|
713 | errpkt(pktmsg); |
---|
714 | return(type = 'E'); |
---|
715 | } |
---|
716 | #ifdef NEWDPL |
---|
717 | /* Reduce prevailing packet length */ |
---|
718 | x = sseqtbl[winlo]; /* Get length of packet we want ACKd */ |
---|
719 | if (x > -1) { /* Only if we have a valid index */ |
---|
720 | if (s_pkt[x].pk_typ == 'D') { /* only for D packets */ |
---|
721 | spsiz = (s_pkt[x].pk_len + 8) >> 1; /* halve it */ |
---|
722 | if (spsiz < 20) spsiz = 20; /* within reason */ |
---|
723 | debug(F101,"input T cut packet length","",spsiz); |
---|
724 | } |
---|
725 | } |
---|
726 | #endif /* NEWDPL */ |
---|
727 | continue; |
---|
728 | } |
---|
729 | } |
---|
730 | /* Got an actual normal packet */ |
---|
731 | |
---|
732 | nak2ack = 0; /* Unset this flag. */ |
---|
733 | y = chkwin(rsn,winlo,wslots); /* Is it in the window? */ |
---|
734 | debug(F101,"input send rsn","",rsn); |
---|
735 | debug(F101,"input send winlo","",winlo); |
---|
736 | debug(F101,"input send chkwin","",y); |
---|
737 | |
---|
738 | if (type == 'Y') { /* Got an ACK */ |
---|
739 | if (y == 0) { /* In current window */ |
---|
740 | if (spackets < 4) /* Error counter doesn't count */ |
---|
741 | numerrs = 0; /* until data phase. */ |
---|
742 | sacktbl[rsn]++; /* Mark the packet as ACK'd */ |
---|
743 | x = sseqtbl[rsn]; /* Get ACK'd packet's buffer index */ |
---|
744 | debug(F101,"bestlen ack x","",x); |
---|
745 | #ifdef NEWDPL |
---|
746 | if (x > -1) { |
---|
747 | acktype = s_pkt[x].pk_typ; /* Get type */ |
---|
748 | debug(F000,"bestlen ack type","",acktype); |
---|
749 | |
---|
750 | if (acktype == 'D') { /* Adjust data packet length */ |
---|
751 | if (spsiz > bestlen) { |
---|
752 | bestlen = spsiz; |
---|
753 | debug(F101,"bestlen B","",bestlen); |
---|
754 | } |
---|
755 | #ifdef DEBUG |
---|
756 | if (deblog) { |
---|
757 | debug(F101,"bestlen retry","",s_pkt[x].pk_rtr); |
---|
758 | debug(F101,"bestlen len","",s_pkt[x].pk_len); |
---|
759 | debug(F101,"bestlen spackets","",spackets); |
---|
760 | } |
---|
761 | #endif /* DEBUG */ |
---|
762 | /* Set new best length */ |
---|
763 | if (s_pkt[x].pk_rtr == 0 && |
---|
764 | s_pkt[x].pk_len + 8 > bestlen) { |
---|
765 | bestlen = s_pkt[x].pk_len + 8; |
---|
766 | if (bestlen > spmax) |
---|
767 | bestlen = spmax; |
---|
768 | debug(F101,"bestlen A","",bestlen); |
---|
769 | } |
---|
770 | #ifdef DEBUG |
---|
771 | if (deblog) { |
---|
772 | debug(F101,"bestlen wslots","",wslots); |
---|
773 | debug(F101,"bestlen maxsend","",maxsend); |
---|
774 | } |
---|
775 | #endif /* DEBUG */ |
---|
776 | /* Slow start */ |
---|
777 | if (slostart && |
---|
778 | (maxsend <= spmax) && |
---|
779 | (rpackets < 11) && |
---|
780 | (numerrs == 0)) { |
---|
781 | spsiz = spsiz << 1; |
---|
782 | debug(F101,"bestlen spsiz A","",spsiz); |
---|
783 | |
---|
784 | /* Creep up to best length */ |
---|
785 | } else if ((spackets > 5) && |
---|
786 | (spsiz < bestlen - 8)) { |
---|
787 | spsiz += (bestlen - spsiz) / 3; |
---|
788 | debug(F101,"bestlen spsiz B","",spsiz); |
---|
789 | |
---|
790 | /* Push the envelope */ |
---|
791 | } else if ((spackets % (wslots + 1) == 0) && |
---|
792 | (spackets > 6) && |
---|
793 | (bestlen < spmax - 8) && |
---|
794 | (spsiz < spmax)) { |
---|
795 | spsiz += (spmax - bestlen) / 3; |
---|
796 | debug(F101,"bestlen spsiz C","",spsiz); |
---|
797 | } |
---|
798 | /* But not too far */ |
---|
799 | if (spsiz > spmax) { |
---|
800 | spsiz = spmax; |
---|
801 | debug(F101,"bestlen spsiz D","",spsiz); |
---|
802 | } |
---|
803 | } |
---|
804 | } |
---|
805 | #endif /* NEWDPL */ |
---|
806 | |
---|
807 | #ifdef CK_TIMERS |
---|
808 | if (rttflg) /* If doing dynamic timers */ |
---|
809 | getrtt(nakstate, rsn); /* call routine to set it. */ |
---|
810 | #endif /* CK_TIMERS */ |
---|
811 | /* |
---|
812 | NOTE: The following statement frees the buffer of the ACK we just got. |
---|
813 | But the upper layers still need the data, like if it's the ACK to an I, |
---|
814 | S, F, D, Z, or just about any kind of packet. So for now, freerbuf() |
---|
815 | deallocates the buffer, but does not erase the data or destroy the pointer |
---|
816 | to it. There's no other single place where these receive buffers can be |
---|
817 | correctly freed (?) ... |
---|
818 | */ |
---|
819 | freerpkt(rsn); /* Free the ACK's buffer */ |
---|
820 | freesbuf(rsn); /* *** Free the sent packet's buffer */ |
---|
821 | if (rsn == winlo) { /* Got the one we want */ |
---|
822 | sacktbl[winlo] = 0; |
---|
823 | winlo = (winlo + 1) % 64; |
---|
824 | debug(F101,"input send rotated send window","",winlo); |
---|
825 | break; /* Return the ACK */ |
---|
826 | } else { |
---|
827 | debug(F101,"input send mark pkt","",rsn); |
---|
828 | continue; /* Otherwise go read another packet */ |
---|
829 | } |
---|
830 | } else if (y == 1 && wslots < 2) { /* (190) ACK for previous */ |
---|
831 | numerrs++; /* == NAK for current, count error */ |
---|
832 | debug(F101,"input send ACK for previous","",rsn); |
---|
833 | freerpkt(rsn); /* Free NAK's buffer */ |
---|
834 | x = resend(winlo); /* Resend current packet */ |
---|
835 | if (x < 0) { |
---|
836 | type = 'E'; |
---|
837 | errpkt(pktmsg); |
---|
838 | break; |
---|
839 | } else continue; /* Resend ok, go read another packet */ |
---|
840 | } else { /* Other cases, just ignore */ |
---|
841 | debug(F101,"input send ACK out of window","",rsn); |
---|
842 | freerpkt(rsn); |
---|
843 | continue; |
---|
844 | } |
---|
845 | } |
---|
846 | if (type == 'N') { /* NAK */ |
---|
847 | numerrs++; /* Count an error */ |
---|
848 | debug(F101,"input send NAK","",rsn); |
---|
849 | #ifdef NEWDPL |
---|
850 | /* Reduce prevailing packet length */ |
---|
851 | x = sseqtbl[rsn]; /* Length of packet that was NAK'd */ |
---|
852 | if (x > -1) { /* If it's a Data packet we've sent */ |
---|
853 | if (s_pkt[x].pk_typ == 'D') { |
---|
854 | spsiz = (s_pkt[x].pk_len + 8) >> 1; /* Halve length */ |
---|
855 | #ifdef COMMENT |
---|
856 | /* This might be a good idea -- haven't tried it ... */ |
---|
857 | if (bestlen > 0 && spsiz > bestlen) |
---|
858 | spsiz = bestlen; |
---|
859 | #endif /* COMMENT */ |
---|
860 | if (spsiz < 20) spsiz = 20; |
---|
861 | debug(F101,"input N cut packet length","",spsiz); |
---|
862 | } |
---|
863 | } |
---|
864 | #endif /* NEWDPL */ |
---|
865 | freerpkt(rsn); /* Free buffer where NAK lies. */ |
---|
866 | if (y == 0) { /* In current window */ |
---|
867 | debug(F100," in window","",0); |
---|
868 | k = sseqtbl[rsn]; /* Get pointer to NAK'd packet. */ |
---|
869 | if (k < 0 || (k > -1 && s_pkt[k].pk_typ == ' ')) { |
---|
870 | x = resend(winlo); /* Packet we haven't sent yet. */ |
---|
871 | } else { |
---|
872 | x = resend(rsn); /* Resend requested packet. */ |
---|
873 | } |
---|
874 | if (x < 0) { /* Resend error is fatal. */ |
---|
875 | type = 'E'; |
---|
876 | errpkt(pktmsg); |
---|
877 | break; |
---|
878 | } else continue; /* Resend ok, go read another packet */ |
---|
879 | } else if ((rsn == (pktnum + 1) % 64)) { /* NAK for next pkt */ |
---|
880 | if (wslots > 1) { |
---|
881 | debug( F101,"NAK for next packet, windowing","",rsn); |
---|
882 | x = resend(winlo); /* Resend window-low */ |
---|
883 | if (x < 0) { |
---|
884 | type = 'E'; |
---|
885 | errpkt(pktmsg); |
---|
886 | break; |
---|
887 | } |
---|
888 | continue; /* Go back and read another pkt */ |
---|
889 | } |
---|
890 | debug(F101,"NAK for next packet, no windowing","",rsn); |
---|
891 | x = (rsn == 0) ? 63 : rsn - 1; |
---|
892 | if (x == 0 && (sndtyp == 'S' || sndtyp == 'I')) { |
---|
893 | resend(0); /* ACK for S or I packet missing */ |
---|
894 | continue; /* so resend the S or I */ |
---|
895 | } |
---|
896 | rsn = x; /* Else, treat NAK(n+1) as ACK(n) */ |
---|
897 | nak2ack = 1; /* Go back and process the ACK */ |
---|
898 | continue; |
---|
899 | } else if (y > 0) { /* NAK for pkt we can't resend */ |
---|
900 | debug(F101," NAK out of window","",rsn); /* bad... */ |
---|
901 | type = 'E'; |
---|
902 | errpkt((CHAR *)"NAK out of window"); |
---|
903 | strcpy((char *)pktmsg,"NAK out of window."); |
---|
904 | break; |
---|
905 | } else continue; /* Ignore other NAKs */ |
---|
906 | } /* End of file-sender NAK handler */ |
---|
907 | |
---|
908 | if (rsn == winlo) { /* Not ACK, NAK, timeout, etc. */ |
---|
909 | debug(F000,"input send unexpected type","",type); |
---|
910 | break; |
---|
911 | } |
---|
912 | } /* End of file-sender section */ |
---|
913 | } /* End of input() while() loop */ |
---|
914 | if (wslots == 1) { |
---|
915 | debug(F100,"input about to flush","",0); |
---|
916 | ttflui(); /* Got what we want, clear input buffer. */ |
---|
917 | } |
---|
918 | #ifndef NEWDPL |
---|
919 | if (!nakstate) /* When sending */ |
---|
920 | rcalcpsz(); /* recalculate size every packet */ |
---|
921 | #endif /* NEWDPL */ |
---|
922 | debug(F000,"input returning type","",type); |
---|
923 | return(rcvtyp = type); /* Success, return packet type. */ |
---|
924 | } |
---|
925 | |
---|
926 | /* D O P A R -- Add an appropriate parity bit to a character */ |
---|
927 | |
---|
928 | /* |
---|
929 | (PWP) this is still used in the Mac terminal emulator, so we have to keep it |
---|
930 | */ |
---|
931 | CHAR |
---|
932 | #ifdef CK_ANSIC |
---|
933 | dopar(register CHAR ch) |
---|
934 | #else |
---|
935 | dopar(ch) register CHAR ch; |
---|
936 | #endif /* CK_ANSIC */ |
---|
937 | { |
---|
938 | register unsigned int a; |
---|
939 | if (!parity |
---|
940 | #ifdef TCPSOCKET |
---|
941 | || (network && /* TELNET BINARY MODE */ |
---|
942 | (ttnproto == NP_TELNET) && (me_binary) ) |
---|
943 | #endif /* TCPSOCKET */ |
---|
944 | ) return((CHAR) (ch & 255)); else a = ch & 127; |
---|
945 | switch (parity) { |
---|
946 | case 'e': return(p_tbl[a]); /* Even */ |
---|
947 | case 'm': return((CHAR) (a | 128)); /* Mark */ |
---|
948 | case 'o': return((CHAR) (p_tbl[a] ^ 128)); /* Odd */ |
---|
949 | case 's': return((CHAR) a); /* Space */ |
---|
950 | default: return((CHAR) a); /* Something illegal */ |
---|
951 | } |
---|
952 | } |
---|
953 | |
---|
954 | #ifdef PARSENSE |
---|
955 | /* P A R C H K -- Check if Kermit packet has parity */ |
---|
956 | |
---|
957 | /* |
---|
958 | Call with s = pointer to packet, start = packet start character, n = length. |
---|
959 | Returns 0 if packet has no parity, -1 on error, or, if packet has parity: |
---|
960 | 'e' for even, 'o' for odd, 'm' for mark. Space parity cannot be sensed. |
---|
961 | So a return value of 0 really means either space or none. |
---|
962 | Returns -2 if parity has already been checked during this protocol operation. |
---|
963 | */ |
---|
964 | int |
---|
965 | #ifdef CK_ANSIC |
---|
966 | parchk(CHAR *s, CHAR start, int n) |
---|
967 | #else |
---|
968 | parchk(s,start,n) CHAR *s, start; int n; |
---|
969 | #endif /* CK_ANSIC */ |
---|
970 | /* parchk */ { |
---|
971 | CHAR s0, s1, s2, s3; |
---|
972 | |
---|
973 | debug(F101,"parchk n","",n); |
---|
974 | debug(F101,"parchk start","",start); |
---|
975 | |
---|
976 | s0 = s[0] & 0x7f; /* Mark field (usually Ctrl-A) */ |
---|
977 | |
---|
978 | if (s0 != start || n < 5) return(-1); /* Not a valid packet */ |
---|
979 | |
---|
980 | /* Look at packet control fields, which never have 8th bit set */ |
---|
981 | /* First check for no parity, most common case. */ |
---|
982 | |
---|
983 | if (((s[0] | s[1] | s[2] | s[3]) & 0x80) == 0) |
---|
984 | return(0); /* No parity or space parity */ |
---|
985 | |
---|
986 | /* Check for mark parity */ |
---|
987 | |
---|
988 | if (((s[0] & s[1] & s[2] & s[3]) & 0x80) == 0x80) |
---|
989 | return('m'); /* Mark parity */ |
---|
990 | |
---|
991 | /* Packet has some kind of parity */ |
---|
992 | /* Make 7-bit copies of control fields */ |
---|
993 | |
---|
994 | s1 = s[1] & 0x7f; /* LEN */ |
---|
995 | s2 = s[2] & 0x7f; /* SEQ */ |
---|
996 | s3 = s[3] & 0x7f; /* TYPE */ |
---|
997 | |
---|
998 | /* Check for even parity */ |
---|
999 | |
---|
1000 | if ((s[0] == p_tbl[s0]) && |
---|
1001 | (s[1] == p_tbl[s1]) && |
---|
1002 | (s[2] == p_tbl[s2]) && |
---|
1003 | (s[3] == p_tbl[s3])) |
---|
1004 | return('e'); |
---|
1005 | |
---|
1006 | /* Check for odd parity */ |
---|
1007 | |
---|
1008 | if ((s[0] != p_tbl[s0]) && |
---|
1009 | (s[1] != p_tbl[s1]) && |
---|
1010 | (s[2] != p_tbl[s2]) && |
---|
1011 | (s[3] != p_tbl[s3])) |
---|
1012 | return('o'); |
---|
1013 | |
---|
1014 | /* Otherwise it's probably line noise. Let checksum calculation catch it. */ |
---|
1015 | |
---|
1016 | return(-1); |
---|
1017 | } |
---|
1018 | #endif /* PARSENSE */ |
---|
1019 | |
---|
1020 | /* |
---|
1021 | Check to make sure timeout intervals are long enough to allow maximum |
---|
1022 | length packets to get through before the timer goes off. If not, the |
---|
1023 | timeout interval is adjusted upwards. |
---|
1024 | |
---|
1025 | This routine is called at the beginning of a transaction, before we |
---|
1026 | know anything about the delay characteristics of the line. It works |
---|
1027 | only for serial communication devices; it trusts the speed reported by |
---|
1028 | the operating system. |
---|
1029 | |
---|
1030 | Call with a timout interval. Returns it, adjusted if necessary. |
---|
1031 | */ |
---|
1032 | int |
---|
1033 | chktimo(timo,flag) int timo, flag; { |
---|
1034 | long cps, z; int x, y; |
---|
1035 | debug(F101,"chktimo timo","",timo); /* Timeout before adjustment */ |
---|
1036 | debug(F101,"chktimo flag","",flag); |
---|
1037 | |
---|
1038 | if (flag) /* Don't change timeout if user */ |
---|
1039 | return(timo); /* gave SET SEND TIMEOUT command. */ |
---|
1040 | debug(F101,"chktimo spmax","",spmax); |
---|
1041 | debug(F101,"chktimo urpsiz","",urpsiz); |
---|
1042 | |
---|
1043 | speed = ttgspd(); /* Get current speed. */ |
---|
1044 | if (speed > 0L && !network) { |
---|
1045 | cps = speed / 10L; /* Convert to chars per second */ |
---|
1046 | if (cps > 0L) { |
---|
1047 | long plen; /* Maximum of send and rcv pkt size */ |
---|
1048 | z = cps * (long) timo; /* Chars per timeout interval */ |
---|
1049 | z -= z / 10L; /* Less 10 percent */ |
---|
1050 | plen = spmax; |
---|
1051 | if (urpsiz > spmax) plen = urpsiz; |
---|
1052 | debug(F101,"chktimo plen","",plen); |
---|
1053 | if (z < plen) { /* Compare with packet size */ |
---|
1054 | x = (int) ((long) plen / cps); /* Adjust if necessary */ |
---|
1055 | y = x / 10; /* Add 10 percent for safety */ |
---|
1056 | if (y < 2) y = 2; /* Or 2 seconds, whichever is more */ |
---|
1057 | x += y; |
---|
1058 | if (x > timo) /* If this is greater than current */ |
---|
1059 | timo = x; /* timeout, change the timeout */ |
---|
1060 | debug(F101,"chktimo new timo","",timo); |
---|
1061 | } |
---|
1062 | } |
---|
1063 | } |
---|
1064 | return(timo); |
---|
1065 | } |
---|
1066 | |
---|
1067 | /* S P A C K -- Construct and send a packet */ |
---|
1068 | |
---|
1069 | /* |
---|
1070 | spack() sends a packet of the given type, sequence number n, with len data |
---|
1071 | characters pointed to by d, in either a regular or extended- length packet, |
---|
1072 | depending on len. Returns the number of bytes actually sent, or else -1 |
---|
1073 | upon failure. Uses global npad, padch, mystch, bctu, data. Leaves packet |
---|
1074 | fully built and null-terminated for later retransmission by resend(). |
---|
1075 | Updates global sndpktl (send-packet length). |
---|
1076 | |
---|
1077 | NOTE: The global pointer "data" is assumed to point into the 7th position |
---|
1078 | of a character array (presumably in packet buffer for the current packet). |
---|
1079 | It was used by getpkt() to build the packet data field. spack() fills in |
---|
1080 | the header to the left of the data pointer (the data pointer is defined |
---|
1081 | in getsbuf() in ckcfn3.c). If the address "d" is the same as "data", then |
---|
1082 | the packet's data field has been built "in place" and need not be copied. |
---|
1083 | */ |
---|
1084 | int |
---|
1085 | #ifdef CK_ANSIC |
---|
1086 | spack(char pkttyp, int n, int len, CHAR *d) |
---|
1087 | #else |
---|
1088 | spack(pkttyp,n,len,d) char pkttyp; int n, len; CHAR *d; |
---|
1089 | #endif /* CK_ANSIC */ |
---|
1090 | /* spack */ { |
---|
1091 | register int i; |
---|
1092 | int j, k, x, lp, longpkt, copy; |
---|
1093 | |
---|
1094 | #ifdef GETMSEC |
---|
1095 | long t1, t2; |
---|
1096 | #endif /* GETMSEC */ |
---|
1097 | |
---|
1098 | register CHAR *cp, *mydata; |
---|
1099 | unsigned crc; |
---|
1100 | |
---|
1101 | debug(F101,"spack n","",n); |
---|
1102 | debug(F111,"spack data",data,data); |
---|
1103 | /* debug(F101,"spack d","",d); */ |
---|
1104 | debug(F101,"spack len","",len); |
---|
1105 | |
---|
1106 | copy = (d != data); /* Flag whether data must be copied */ |
---|
1107 | longpkt = (len + bctl + 2) > 94; /* Decide whether it's a long packet */ |
---|
1108 | mydata = data - 7 + (longpkt ? 0 : 3); /* Starting position of header */ |
---|
1109 | debug(F101," mydata","",mydata); |
---|
1110 | |
---|
1111 | k = sseqtbl[n]; /* Packet structure info for pkt n */ |
---|
1112 | debug(F101," sseqtbl[n]","",k); |
---|
1113 | if (k < 0) { |
---|
1114 | debug(F101,"spack sending packet out of window","",n); |
---|
1115 | } else { /* Record packet info */ |
---|
1116 | s_pkt[k].pk_adr = mydata; /* Remember address of packet. */ |
---|
1117 | s_pkt[k].pk_seq = n; /* Record sequence number */ |
---|
1118 | s_pkt[k].pk_typ = pkttyp; /* Record packet type */ |
---|
1119 | } |
---|
1120 | spktl = 0; /* Initialize length of this packet */ |
---|
1121 | i = 0; /* and position in packet. */ |
---|
1122 | |
---|
1123 | /* Now fill the packet */ |
---|
1124 | |
---|
1125 | mydata[i++] = mystch; /* MARK */ |
---|
1126 | lp = i++; /* Position of LEN, fill in later */ |
---|
1127 | |
---|
1128 | mydata[i++] = tochar(n); /* SEQ field */ |
---|
1129 | mydata[i++] = pkttyp; /* TYPE field */ |
---|
1130 | j = len + bctl; /* Length of data + block check */ |
---|
1131 | if (longpkt) { /* Long packet? */ |
---|
1132 | int x; /* Work around SCO Xenix/286 */ |
---|
1133 | x = j / 95; /* compiler bug... */ |
---|
1134 | mydata[lp] = tochar(0); /* Yes, set LEN to zero */ |
---|
1135 | mydata[i++] = tochar(x); /* High part */ |
---|
1136 | mydata[i++] = tochar(j % 95); /* Low part */ |
---|
1137 | mydata[i] = '\0'; /* Header checksum */ |
---|
1138 | mydata[i++] = tochar(chk1(mydata+lp)); |
---|
1139 | } else mydata[lp] = tochar(j+2); /* Normal LEN */ |
---|
1140 | |
---|
1141 | if (copy) /* Data field built in place? */ |
---|
1142 | for ( ; len--; i++) mydata[i] = *d++; /* No, must copy. */ |
---|
1143 | else /* Otherwise, */ |
---|
1144 | i += len; /* Just skip past data field. */ |
---|
1145 | mydata[i] = '\0'; /* Null-terminate for checksum calc. */ |
---|
1146 | |
---|
1147 | switch (bctu) { /* Block check */ |
---|
1148 | case 1: /* 1 = 6-bit chksum */ |
---|
1149 | mydata[i++] = tochar(chk1(mydata+lp)); |
---|
1150 | break; |
---|
1151 | case 2: /* 2 = 12-bit chksum */ |
---|
1152 | j = chk2(mydata+lp); |
---|
1153 | mydata[i++] = (unsigned)tochar((j >> 6) & 077); |
---|
1154 | mydata[i++] = (unsigned)tochar(j & 077); |
---|
1155 | break; |
---|
1156 | case 3: /* 3 = 16-bit CRC */ |
---|
1157 | crc = chk3(mydata+lp,parity); |
---|
1158 | mydata[i++] = (unsigned)tochar(((crc & 0170000)) >> 12); |
---|
1159 | mydata[i++] = (unsigned)tochar((crc >> 6) & 077); |
---|
1160 | mydata[i++] = (unsigned)tochar(crc & 077); |
---|
1161 | break; |
---|
1162 | case 4: /* 2 = 12-bit chksum, blank-free */ |
---|
1163 | j = chk2(mydata+lp); |
---|
1164 | mydata[i++] = |
---|
1165 | (unsigned)(tochar((unsigned)(((j >> 6) & 077) + 1))); |
---|
1166 | mydata[i++] = (unsigned)(tochar((unsigned)((j & 077) + 1))); |
---|
1167 | break; |
---|
1168 | } |
---|
1169 | mydata[i++] = seol; /* End of line (packet terminator) */ |
---|
1170 | #ifdef TCPSOCKET |
---|
1171 | /* |
---|
1172 | If TELNET connection and packet terminator is carriage return, |
---|
1173 | we must stuff either LF or NUL, according to SET TELNET NEWLINE-MODE |
---|
1174 | (tn_nlm), to meet the TELNET specification, unless user said RAW. |
---|
1175 | |
---|
1176 | If NEWLINE-MODE is set to LF instead of CR, we still send CR-NUL |
---|
1177 | on a NVT connection and CR on a binary connection. |
---|
1178 | */ |
---|
1179 | if (seol == CR && network && ttnproto == NP_TELNET) { |
---|
1180 | switch (me_binary ? tn_b_nlm : tn_nlm) { /* NVT or BINARY */ |
---|
1181 | case TNL_CR: |
---|
1182 | break; |
---|
1183 | case TNL_CRNUL: |
---|
1184 | mydata[i++] = NUL ; |
---|
1185 | break; |
---|
1186 | case TNL_CRLF: |
---|
1187 | mydata[i++] = LF ; |
---|
1188 | break; |
---|
1189 | } |
---|
1190 | } |
---|
1191 | #endif /* TCPSOCKET */ |
---|
1192 | mydata[i] = '\0'; /* Terminate string */ |
---|
1193 | logpkt('s',n,mydata); /* Log packet */ |
---|
1194 | |
---|
1195 | /* (PWP) add the parity quickly at the end */ |
---|
1196 | switch (parity) { |
---|
1197 | case 'e': /* Even */ |
---|
1198 | for (cp = &mydata[i-1]; cp >= mydata; cp--) |
---|
1199 | *cp = p_tbl[*cp]; |
---|
1200 | break; |
---|
1201 | case 'm': /* Mark */ |
---|
1202 | for (cp = &mydata[i-1]; cp >= mydata; cp--) |
---|
1203 | *cp |= 128; |
---|
1204 | break; |
---|
1205 | case 'o': /* Odd */ |
---|
1206 | for (cp = &mydata[i-1]; cp >= mydata; cp--) |
---|
1207 | *cp = p_tbl[*cp] ^ 128; |
---|
1208 | break; |
---|
1209 | case 's': /* Space */ |
---|
1210 | for (cp = &mydata[i-1]; cp >= mydata; cp--) |
---|
1211 | *cp &= 127; |
---|
1212 | break; |
---|
1213 | } |
---|
1214 | if (pktpaus) msleep(pktpaus); /* Pause if requested */ |
---|
1215 | if (npad) ttol(padbuf,npad); /* Send any padding */ |
---|
1216 | #ifdef CK_TIMERS |
---|
1217 | if (pkttyp == 'N') |
---|
1218 | srttbl[n > 0 ? n-1 : 63] = gtimer(); |
---|
1219 | else |
---|
1220 | srttbl[n] = gtimer(); |
---|
1221 | #endif /* CK_TIMERS */ |
---|
1222 | spktl = i; /* Remember packet length */ |
---|
1223 | if (k > -1) |
---|
1224 | s_pkt[k].pk_len = spktl; /* also in packet info structure */ |
---|
1225 | |
---|
1226 | #ifdef GETMSEC |
---|
1227 | if (deblog) t1 = getmsec(); |
---|
1228 | #endif /* GETMSEC */ |
---|
1229 | |
---|
1230 | x = ttol(mydata,spktl); |
---|
1231 | if (spktl > maxsend) maxsend = spktl; |
---|
1232 | |
---|
1233 | #ifdef GETMSEC |
---|
1234 | if (deblog) { |
---|
1235 | t2 = getmsec(); |
---|
1236 | if (t2 > -1L && t1 > -1L) |
---|
1237 | debug(F101,"spack ttol time","",t2-t1); |
---|
1238 | else |
---|
1239 | debug(F100,"spack ttol time error","",0); |
---|
1240 | } |
---|
1241 | #endif /* GETMSEC */ |
---|
1242 | |
---|
1243 | debug(F101,"spack ttol returns","",x); |
---|
1244 | if (x < 0) |
---|
1245 | return(x); |
---|
1246 | sndtyp = pkttyp; /* Remember packet type for echos */ |
---|
1247 | spackets++; /* Count it. */ |
---|
1248 | flco += spktl; /* Count the characters */ |
---|
1249 | tlco += spktl; /* for statistics... */ |
---|
1250 | dumpsbuf(); /* Dump send buffers to debug log */ |
---|
1251 | debug(F100,"spack about to call screen","",0); |
---|
1252 | debug(F111," with mydata=",mydata,n); |
---|
1253 | screen(SCR_PT,pkttyp,(long)n,(char *)mydata); /* Update screen */ |
---|
1254 | return(spktl); /* Return length */ |
---|
1255 | } |
---|
1256 | |
---|
1257 | /* C H K 1 -- Compute a type-1 Kermit 6-bit checksum. */ |
---|
1258 | |
---|
1259 | int |
---|
1260 | chk1(pkt) register CHAR *pkt; { |
---|
1261 | register unsigned int chk; |
---|
1262 | chk = chk2(pkt); |
---|
1263 | chk = (((chk & 0300) >> 6) + chk) & 077; |
---|
1264 | return((int) chk); |
---|
1265 | } |
---|
1266 | |
---|
1267 | /* C H K 2 -- Compute the numeric sum of all the bytes in the packet. */ |
---|
1268 | |
---|
1269 | unsigned int |
---|
1270 | chk2(pkt) register CHAR *pkt; { |
---|
1271 | register long chk; register unsigned int m; |
---|
1272 | m = (parity) ? 0177 : 0377; |
---|
1273 | for (chk = 0; *pkt != '\0'; pkt++) |
---|
1274 | chk += *pkt & m; |
---|
1275 | return((unsigned int) (chk & 07777)); |
---|
1276 | } |
---|
1277 | |
---|
1278 | |
---|
1279 | /* C H K 3 -- Compute a type-3 Kermit block check. */ |
---|
1280 | /* |
---|
1281 | Calculate the 16-bit CRC-CCITT of a null-terminated string using a lookup |
---|
1282 | table. Assumes the argument string contains no embedded nulls. |
---|
1283 | */ |
---|
1284 | unsigned int |
---|
1285 | chk3(pkt,parity) register CHAR *pkt; int parity; { |
---|
1286 | register long c, crc; |
---|
1287 | register unsigned int m; |
---|
1288 | m = (parity) ? 0177 : 0377; |
---|
1289 | for (crc = 0; *pkt != '\0'; pkt++) { |
---|
1290 | c = crc ^ (long)(*pkt & m); |
---|
1291 | crc = (crc >> 8) ^ (crcta[(c & 0xF0) >> 4] ^ crctb[c & 0x0F]); |
---|
1292 | } |
---|
1293 | return((unsigned int) (crc & 0xFFFF)); |
---|
1294 | } |
---|
1295 | |
---|
1296 | int |
---|
1297 | nxtpkt() { /* Called by file sender */ |
---|
1298 | int j, n; |
---|
1299 | |
---|
1300 | debug(F101,"nxtpkt pktnum","",pktnum); |
---|
1301 | debug(F101,"nxtpkt winlo ","",winlo); |
---|
1302 | n = (pktnum + 1) % 64; /* Increment packet number mod 64 */ |
---|
1303 | #ifdef COMMENT |
---|
1304 | /* |
---|
1305 | Suggested by Alan Grieg. A packet can be sent out of window in |
---|
1306 | circumstances involving acks received out of order, ... Have to think |
---|
1307 | about this... |
---|
1308 | */ |
---|
1309 | if (chkwin(n,winlo,wslots)) { |
---|
1310 | debug(F101,"nxtpkt n not in window","",n); |
---|
1311 | return(-1); |
---|
1312 | } |
---|
1313 | #endif |
---|
1314 | j = getsbuf(n); /* Get a buffer for packet n */ |
---|
1315 | if (j < 0) { |
---|
1316 | debug(F101,"nxtpkt can't getsbuf","",j); |
---|
1317 | return(-1); |
---|
1318 | } |
---|
1319 | pktnum = n; |
---|
1320 | debug(F101,"nxtpkt bumped pktnum to","",pktnum); |
---|
1321 | return(0); |
---|
1322 | } |
---|
1323 | |
---|
1324 | /* Functions for sending ACKs and NAKs */ |
---|
1325 | |
---|
1326 | /* Note, we should only ACK the packet at window-low (winlo) */ |
---|
1327 | /* However, if an old packet arrives again (e.g. because the ACK we sent */ |
---|
1328 | /* earlier was lost), we ACK it again. */ |
---|
1329 | |
---|
1330 | int |
---|
1331 | ack() { /* Acknowledge the current packet. */ |
---|
1332 | return(ackns(winlo,(CHAR *)"")); |
---|
1333 | } |
---|
1334 | |
---|
1335 | int |
---|
1336 | ackns(n,s) int n; CHAR *s; { /* Acknowledge packet n */ |
---|
1337 | int j, k; |
---|
1338 | debug(F111,"ackns",s,n); |
---|
1339 | |
---|
1340 | k = rseqtbl[n]; /* First find received packet n. */ |
---|
1341 | debug(F101,"ackns k","",k); |
---|
1342 | freesbuf(n); /* Free current send-buffer, if any */ |
---|
1343 | if ((j = getsbuf(n)) < 0) { |
---|
1344 | /* This can happen if we have to re-ACK an old packet that has */ |
---|
1345 | /* already left the window. It does no harm. */ |
---|
1346 | debug(F101,"ackns can't getsbuf","",n); |
---|
1347 | } |
---|
1348 | spack('Y',n,(int)strlen((char *)s),s); /* Now send it. */ |
---|
1349 | debug(F101,"ackns winlo","",winlo); |
---|
1350 | debug(F101,"ackns n","",n); |
---|
1351 | if (n == winlo) { /* If we're acking winlo */ |
---|
1352 | if (k > -1) |
---|
1353 | freerbuf(k); /* don't need it any more */ |
---|
1354 | if (j > -1) |
---|
1355 | freesbuf(j); /* and don't need to keep ACK either */ |
---|
1356 | winlo = (winlo + 1) % 64; |
---|
1357 | } |
---|
1358 | return(0); |
---|
1359 | } |
---|
1360 | |
---|
1361 | int |
---|
1362 | ackn(n) int n; { /* Send ACK for packet number n */ |
---|
1363 | return(ackns(n,(CHAR *)"")); |
---|
1364 | } |
---|
1365 | |
---|
1366 | int |
---|
1367 | ack1(s) CHAR *s; { /* Send an ACK with data. */ |
---|
1368 | debug(F110,"ack1",(char *) s,0); |
---|
1369 | return(ackns(winlo, s)); |
---|
1370 | } |
---|
1371 | |
---|
1372 | /* N A C K -- Send a Negative ACKnowledgment. */ |
---|
1373 | /* |
---|
1374 | Call with the packet number, n, to be NAK'd. |
---|
1375 | Returns -1 if that packet has been NAK'd too many times, otherwise 0. |
---|
1376 | Btw, it is not right to return 0 under error conditions. This is |
---|
1377 | done because the -1 code is used for cancelling the file transfer. |
---|
1378 | More work is needed here. |
---|
1379 | */ |
---|
1380 | int |
---|
1381 | nack(n) int n; { |
---|
1382 | int i; |
---|
1383 | |
---|
1384 | if (n < 0 || n > 63) { |
---|
1385 | debug(F101,"nack bad pkt num","",n); |
---|
1386 | return(0); |
---|
1387 | } else debug(F101,"nack","",n); |
---|
1388 | if ((i = sseqtbl[n]) < 0) { /* If necessary */ |
---|
1389 | if (getsbuf(n) < 0) { /* get a buffer for this NAK */ |
---|
1390 | debug(F101,"nack can't getsbuf","",n); |
---|
1391 | return(0); |
---|
1392 | } else i = sseqtbl[n]; /* New slot number */ |
---|
1393 | } |
---|
1394 | if (s_pkt[i].pk_rtr++ > maxtry) /* How many times have we done this? */ |
---|
1395 | return(-1); /* Too many... */ |
---|
1396 | |
---|
1397 | /* Note, don't free this buffer. Eventually an ACK will come, and that */ |
---|
1398 | /* will set it free. If not, well, it's back to ground zero anyway... */ |
---|
1399 | |
---|
1400 | spack('N',n,0,(CHAR *) ""); /* NAKs never have data. */ |
---|
1401 | return(0); |
---|
1402 | } |
---|
1403 | |
---|
1404 | #ifndef NEWDPL /* This routine no longer used */ |
---|
1405 | /* |
---|
1406 | * (PWP) recalculate the optimal packet length in the face of errors. |
---|
1407 | * This is a modified version of the algorithm by John Chandler in Kermit/370, |
---|
1408 | * see "Dynamic Packet Size Control", Kermit News, V2 #1, June 1988. |
---|
1409 | * |
---|
1410 | * This implementation minimizes the total overhead equation, which is |
---|
1411 | * |
---|
1412 | * Total chars = file_chars + (header_len * num_packs) |
---|
1413 | * + (errors * (header_len + packet_len)) |
---|
1414 | * |
---|
1415 | * Differentiate with respect to number of chars, solve for packet_len, get: |
---|
1416 | * |
---|
1417 | * packet_len = sqrt (file_chars * header_len / errors) |
---|
1418 | */ |
---|
1419 | |
---|
1420 | /* |
---|
1421 | (FDC) New super-simple algorithm. If there was an error in the most recent |
---|
1422 | packet exchange, cut the send-packet size in half, down to a minimum of 20. |
---|
1423 | If there was no error, increase the size by 5/4, up to the maximum negotiated |
---|
1424 | length. Seems to be much more responsive than previous algorithm, which took |
---|
1425 | forever to recover the original packet length, and it also went crazy under |
---|
1426 | certain conditions. |
---|
1427 | |
---|
1428 | Here's another idea for packet length resizing that keeps a history of the |
---|
1429 | last n packets. Push a 1 into the left end of an n-bit shift register if the |
---|
1430 | current packet is good, otherwise push a zero. The current n-bit value, w, of |
---|
1431 | this register is a weighted sum of the noise hits for the last n packets, with |
---|
1432 | the most recent weighing the most. The current packet length is some function |
---|
1433 | of w and the negotiated packet length, like: |
---|
1434 | |
---|
1435 | (2^n - w) / (2^n) * (negotiated length) |
---|
1436 | |
---|
1437 | If the present resizing method causes problems, think about this one a little |
---|
1438 | more. |
---|
1439 | */ |
---|
1440 | VOID |
---|
1441 | rcalcpsz() { |
---|
1442 | |
---|
1443 | #ifdef COMMENT |
---|
1444 | /* Old way */ |
---|
1445 | register long x, q; |
---|
1446 | if (numerrs == 0) return; /* bounds check just in case */ |
---|
1447 | |
---|
1448 | /* overhead on a data packet is npad+5+bctr, plus 3 if extended packet */ |
---|
1449 | /* an ACK is 5+bctr */ |
---|
1450 | |
---|
1451 | /* first set x = per packet overhead */ |
---|
1452 | if (wslots > 1) /* Sliding windows */ |
---|
1453 | x = (long) (npad+5+bctr); /* packet only, don't count ack */ |
---|
1454 | else /* Stop-n-wait */ |
---|
1455 | x = (long) (npad+5+3+bctr+5+bctr); /* count packet and ack. */ |
---|
1456 | |
---|
1457 | /* then set x = packet length ** 2 */ |
---|
1458 | x = x * ( ffc / (long) numerrs); /* careful of overflow */ |
---|
1459 | |
---|
1460 | /* calculate the long integer sqrt(x) quickly */ |
---|
1461 | q = 500; |
---|
1462 | q = (q + x/q) >> 1; |
---|
1463 | q = (q + x/q) >> 1; |
---|
1464 | q = (q + x/q) >> 1; |
---|
1465 | q = (q + x/q) >> 1; /* should converge in about 4 steps */ |
---|
1466 | if ((q > 94) && (q < 130)) /* break-even point for long packets */ |
---|
1467 | q = 94; |
---|
1468 | if (q > spmax) q = spmax; /* maximum bounds */ |
---|
1469 | if (q < 10) q = 10; /* minimum bounds */ |
---|
1470 | spsiz = q; /* set new send packet size */ |
---|
1471 | debug(F101,"rcalcpsiz","",q); |
---|
1472 | #else |
---|
1473 | /* New way */ |
---|
1474 | debug(F101,"rcalcpsiz numerrs","",numerrs); |
---|
1475 | debug(F101,"rcalcpsiz spsiz","",spsiz); |
---|
1476 | if (spackets < 3) { |
---|
1477 | numerrs = 0; |
---|
1478 | return; |
---|
1479 | } |
---|
1480 | if (numerrs) |
---|
1481 | spsiz = spsiz / 2; |
---|
1482 | else |
---|
1483 | spsiz = (spsiz / 4) * 5; |
---|
1484 | if (spsiz < 20) spsiz = 20; |
---|
1485 | if (spsiz > spmax) spsiz = spmax; |
---|
1486 | debug(F101,"rcalcpsiz new spsiz","",spsiz); |
---|
1487 | numerrs = 0; |
---|
1488 | #endif /* COMMENT */ |
---|
1489 | } |
---|
1490 | #endif /* NEWDPL */ |
---|
1491 | |
---|
1492 | /* R E S E N D -- Retransmit packet n. */ |
---|
1493 | |
---|
1494 | /* |
---|
1495 | Returns 0 or positive on success (the number of retries for packet n). |
---|
1496 | On failure, returns a negative number, and an error message is placed |
---|
1497 | in recpkt. |
---|
1498 | */ |
---|
1499 | int |
---|
1500 | resend(n) int n; { /* Send packet n again. */ |
---|
1501 | int j, k, x; |
---|
1502 | #ifdef GETMSEC |
---|
1503 | long t1, t2; |
---|
1504 | #endif /* GETMSEC */ |
---|
1505 | |
---|
1506 | debug(F101,"resend seq","",n); |
---|
1507 | |
---|
1508 | k = chkwin(n,winlo,wslots); /* See if packet in current window */ |
---|
1509 | j = -1; /* Assume it's lost */ |
---|
1510 | if (k == 0) j = sseqtbl[n]; /* See if we still have a copy of it */ |
---|
1511 | if (k != 0 || j < 0) { /* If not.... */ |
---|
1512 | if (nakstate && k == 1) { |
---|
1513 | /* |
---|
1514 | Packet n is in the previous window and we are the file receiver. |
---|
1515 | We already sent the ACK and deallocated its buffer so we can't just |
---|
1516 | retransmit the ACK. Rather than give up, we try some tricks... |
---|
1517 | */ |
---|
1518 | if (n == 0 && spackets < 63 && myinit[0]) { /* ACK to Send-Init */ |
---|
1519 | /* |
---|
1520 | If the packet number is 0, and we're at the beginning of a protocol |
---|
1521 | operation (spackets < 63), then we have to resend the ACK to an I or S |
---|
1522 | packet, complete with parameters in the data field. So we take a chance and |
---|
1523 | send a copy of the parameters in an ACK packet with block check type 1. |
---|
1524 | */ |
---|
1525 | int bctlsav; /* Temporary storage */ |
---|
1526 | int bctusav; |
---|
1527 | bctlsav = bctl; /* Save current block check length */ |
---|
1528 | bctusav = bctu; /* and type */ |
---|
1529 | bctu = bctl = 1; /* Set block check to 1 */ |
---|
1530 | spack('Y',0,(int)strlen((char *)myinit),(CHAR *)myinit); |
---|
1531 | logpkt('#',n,(CHAR *)"<reconstructed>"); /* Log it */ |
---|
1532 | bctu = bctusav; /* Restore block check type */ |
---|
1533 | bctl = bctlsav; /* and length */ |
---|
1534 | |
---|
1535 | } else { /* Not the first packet */ |
---|
1536 | /* |
---|
1537 | It's not the first packet of the protocol operation. It's some other packet |
---|
1538 | that we have already ACK'd and forgotten about. So we take a chance and |
---|
1539 | send an empty ACK using the current block-check type. Usually this will |
---|
1540 | work out OK (like when acking Data packets), and no great harm will be done |
---|
1541 | if it was some other kind of packet (F, etc). If we are requesting an |
---|
1542 | interruption of the file transfer, the flags are still set, so we'll catch |
---|
1543 | up on the next packet. |
---|
1544 | */ |
---|
1545 | spack('Y',n,0,(CHAR *) ""); |
---|
1546 | } |
---|
1547 | retrans++; |
---|
1548 | screen(SCR_PT,'%',(long)pktnum,"Retransmission"); |
---|
1549 | return(0); |
---|
1550 | } else { |
---|
1551 | /* |
---|
1552 | Packet number is not in current or previous window. We seem to hit this |
---|
1553 | code occasionally at the beginning of a transaction, for apparently no good |
---|
1554 | reason. Let's just log it for debugging, send nothing, and try to proceed |
---|
1555 | with the protocol rather than killing it. |
---|
1556 | */ |
---|
1557 | debug(F101,"RESEND PKT NOT IN WINDOW","",n); |
---|
1558 | debug(F101,"RESEND k","",k); |
---|
1559 | #ifdef COMMENT |
---|
1560 | sprintf((char *)pktmsg, |
---|
1561 | " resend error: NIW, n=%d, k=%d.",n,k); |
---|
1562 | return(-2); |
---|
1563 | #else |
---|
1564 | return(0); |
---|
1565 | #endif /* COMMENT */ |
---|
1566 | } |
---|
1567 | } |
---|
1568 | |
---|
1569 | /* OK, it's in the window and it's not lost. */ |
---|
1570 | |
---|
1571 | debug(F101,"resend pktinfo index","",k); |
---|
1572 | |
---|
1573 | if (s_pkt[j].pk_rtr++ > maxtry) { /* Found it but over retry limit */ |
---|
1574 | strcpy((char *)pktmsg,"Too many retries."); |
---|
1575 | return(-1); |
---|
1576 | } |
---|
1577 | debug(F101," retry","",s_pkt[j].pk_rtr); /* OK so far */ |
---|
1578 | dumpsbuf(); /* (debugging) */ |
---|
1579 | if (s_pkt[j].pk_typ == ' ') { /* Incompletely formed packet */ |
---|
1580 | if (nakstate) { /* (This shouldn't happen any more) */ |
---|
1581 | nack(n); |
---|
1582 | retrans++; |
---|
1583 | screen(SCR_PT,'%',(long)pktnum,"(resend)"); |
---|
1584 | return(s_pkt[j].pk_rtr); |
---|
1585 | } else { /* No packet to resend! */ |
---|
1586 | #ifdef COMMENT |
---|
1587 | /* |
---|
1588 | This happened (once) while sending a file with 2 window slots and typing |
---|
1589 | X to the sender to cancel the file. But since we're cancelling anyway, |
---|
1590 | there's no need to give a scary message. |
---|
1591 | */ |
---|
1592 | sprintf((char *)pktmsg, |
---|
1593 | "resend logic error: NPS, n=%d, j=%d.",n,j); |
---|
1594 | return(-2); |
---|
1595 | #else |
---|
1596 | /* Just ignore it. */ |
---|
1597 | return(0); |
---|
1598 | #endif /* COMMENT */ |
---|
1599 | } |
---|
1600 | } |
---|
1601 | #ifdef GETMSEC |
---|
1602 | if (deblog) t1 = getmsec(); |
---|
1603 | #endif /* GETMSEC */ |
---|
1604 | |
---|
1605 | /* Everything ok, send the packet */ |
---|
1606 | #ifdef CK_TIMERS |
---|
1607 | srttbl[n] = gtimer(); /* Update the timer */ |
---|
1608 | #endif /* CK_TIMERS */ |
---|
1609 | x = ttol(s_pkt[j].pk_adr,s_pkt[j].pk_len); |
---|
1610 | |
---|
1611 | #ifdef GETMSEC |
---|
1612 | if (deblog) { |
---|
1613 | t2 = getmsec(); |
---|
1614 | if (t2 > -1L && t1 > -1L) |
---|
1615 | debug(F101,"resend ttol time","",t2-t1); |
---|
1616 | else |
---|
1617 | debug(F100,"resend ttol time error","",0); |
---|
1618 | } |
---|
1619 | #endif /* GETMSEC */ |
---|
1620 | debug(F101,"resend ttol returns","",x); |
---|
1621 | |
---|
1622 | retrans++; /* Count a retransmission */ |
---|
1623 | screen(SCR_PT,'%',(long)pktnum,"(resend)"); /* Tell user about resend */ |
---|
1624 | logpkt('S',n,s_pkt[j].pk_adr); /* Log the resent packet */ |
---|
1625 | return(s_pkt[j].pk_rtr); /* Return the number of retries. */ |
---|
1626 | } |
---|
1627 | |
---|
1628 | int |
---|
1629 | errpkt(reason) CHAR *reason; { /* Send an error packet. */ |
---|
1630 | int x, y; |
---|
1631 | encstr(reason); |
---|
1632 | y = spack('E',pktnum,size,data); |
---|
1633 | x = quiet; quiet = 1; /* Close files silently. */ |
---|
1634 | clsif(); clsof(1); |
---|
1635 | quiet = x; |
---|
1636 | #ifdef COMMENT |
---|
1637 | screen(SCR_TC,0,0l,""); |
---|
1638 | #endif /* COMMENT */ |
---|
1639 | if (what < W_CONNECT) |
---|
1640 | xitsta |= what; /* Remember what failed. */ |
---|
1641 | success = 0; |
---|
1642 | return(y); |
---|
1643 | } |
---|
1644 | |
---|
1645 | /* scmd() -- Send a packet of the given type */ |
---|
1646 | |
---|
1647 | int |
---|
1648 | #ifdef CK_ANSIC |
---|
1649 | scmd(char t, CHAR *dat) |
---|
1650 | #else |
---|
1651 | scmd(t,dat) char t; CHAR *dat; |
---|
1652 | #endif /* CK_ANSIC */ |
---|
1653 | /* scmd */ { |
---|
1654 | if (encstr(dat) < 0) /* Encode the command string */ |
---|
1655 | return(-1); |
---|
1656 | spack(t,pktnum,size,data); |
---|
1657 | return(0); |
---|
1658 | } |
---|
1659 | |
---|
1660 | int |
---|
1661 | srinit(reget, retrieve) int reget, retrieve; { /* Send R, H, or J packet */ |
---|
1662 | if (encstr((CHAR *)cmarg) < 0) /* Encode the filename. */ |
---|
1663 | return(-1); |
---|
1664 | if (retrieve) |
---|
1665 | spack((char)'H',pktnum,size,data); /* Send the packet. */ |
---|
1666 | else |
---|
1667 | spack((char)(reget ? 'J' : 'R'),pktnum,size,data); /* Send the packet. */ |
---|
1668 | return(0); |
---|
1669 | } |
---|
1670 | |
---|
1671 | /* K S T A R T -- Checks for a Kermit packet while in terminal mode. */ |
---|
1672 | |
---|
1673 | #ifdef CK_APC |
---|
1674 | int |
---|
1675 | #ifdef CK_ANSIC |
---|
1676 | kstart(CHAR ch) |
---|
1677 | #else |
---|
1678 | kstart(ch) CHAR ch; |
---|
1679 | #endif /* CK_ANSIC */ |
---|
1680 | /* kstart */ { |
---|
1681 | static int buflen = 94; |
---|
1682 | static CHAR buf[95]; |
---|
1683 | static CHAR * p = NULL; |
---|
1684 | extern CHAR stchr, eol; |
---|
1685 | |
---|
1686 | if (ch == stchr) { /* Start of packet */ |
---|
1687 | p = buf; |
---|
1688 | *p = ch; |
---|
1689 | debug(F101,"kstart SOP","",ch); |
---|
1690 | } else if (ch == eol) { /* End of packet */ |
---|
1691 | if (p) { |
---|
1692 | p++; |
---|
1693 | if (p - buf < 94 ) { |
---|
1694 | int rc = 0; |
---|
1695 | *p = ch; |
---|
1696 | p++; |
---|
1697 | *p = NUL; |
---|
1698 | if (rc = chkspkt((char *)buf)) |
---|
1699 | debug(F111,"kstart EOP", buf, ch); |
---|
1700 | p = NULL; |
---|
1701 | if (!rc) return(0); |
---|
1702 | return(rc == 1 ? PROTO_K + 1 : 0 - (PROTO_K + 1)); |
---|
1703 | } else { |
---|
1704 | p = NULL; |
---|
1705 | } |
---|
1706 | } |
---|
1707 | } else if (p) { |
---|
1708 | p++; |
---|
1709 | if (p - buf < 94) |
---|
1710 | *p = ch; |
---|
1711 | else |
---|
1712 | p = NULL; |
---|
1713 | } |
---|
1714 | return(0); |
---|
1715 | } |
---|
1716 | |
---|
1717 | #ifdef CK_XYZ |
---|
1718 | |
---|
1719 | /* Z S T A R T -- Checks for a ZMODEM packet while in terminal mode. */ |
---|
1720 | |
---|
1721 | int |
---|
1722 | #ifdef CK_ANSIC |
---|
1723 | zstart(CHAR ch) |
---|
1724 | #else |
---|
1725 | zstart(ch) CHAR ch; |
---|
1726 | #endif /* CK_ANSIC */ |
---|
1727 | /* zstart */ { |
---|
1728 | static CHAR * matchstr = (CHAR *) "\030B00"; |
---|
1729 | /* "rz\r**\030B00000000000000\r\033J\021"; */ |
---|
1730 | static CHAR * p = NULL; |
---|
1731 | |
---|
1732 | if (!ch) |
---|
1733 | return(0); |
---|
1734 | if (!p) |
---|
1735 | p = matchstr; |
---|
1736 | |
---|
1737 | if (ch == *p) { |
---|
1738 | p++; |
---|
1739 | if (*p == '\0') { |
---|
1740 | p = matchstr; |
---|
1741 | debug(F100, "zstart Zmodem SOP","",0); |
---|
1742 | return(PROTO_Z + 1); |
---|
1743 | } |
---|
1744 | } else |
---|
1745 | p = matchstr; |
---|
1746 | return(0); |
---|
1747 | } |
---|
1748 | #endif /* CK_XYZ */ |
---|
1749 | |
---|
1750 | /* C H K S P K T -- Check if buf contains a valid S or I packet */ |
---|
1751 | |
---|
1752 | int |
---|
1753 | chkspkt(buf) char *buf; { |
---|
1754 | int buflen; |
---|
1755 | int len = -1; |
---|
1756 | CHAR chk; |
---|
1757 | char type = 0; |
---|
1758 | char *s = buf; |
---|
1759 | |
---|
1760 | if (!buf) return(0); |
---|
1761 | buflen = strlen(buf); |
---|
1762 | if (buflen < 5) return(0); /* Too short */ |
---|
1763 | if (*s++ != stchr) return(0); /* SOH */ |
---|
1764 | len = xunchar(*s++); /* Length */ |
---|
1765 | if (len < 0) return(0); |
---|
1766 | if (*s++ != SP) return(0); /* Sequence number */ |
---|
1767 | type = *s++; /* Type */ |
---|
1768 | if (type != 'S' && type != 'I') |
---|
1769 | return(0); |
---|
1770 | if (buflen < len + 2) return(0); |
---|
1771 | s += (len - 3); /* Position of checksum */ |
---|
1772 | chk = (CHAR) (*s); /* Checksum */ |
---|
1773 | *s = NUL; |
---|
1774 | if (xunchar(chk) != chk1((CHAR *) (buf+1))) return(0); /* Check it */ |
---|
1775 | *s = chk; |
---|
1776 | return(type == 'S' ? 1 : 2); |
---|
1777 | } |
---|
1778 | #endif /* CK_APC */ |
---|
1779 | |
---|
1780 | /* R P A C K -- Read a Packet */ |
---|
1781 | |
---|
1782 | /* |
---|
1783 | rpack reads a packet and returns the packet type, or else Q if the |
---|
1784 | packet was invalid, or T if a timeout occurred. Upon successful return, sets |
---|
1785 | the values of global rsn (received sequence number), rln (received |
---|
1786 | data length), and rdatap (pointer to null-terminated data field), and |
---|
1787 | returns the packet type. |
---|
1788 | */ |
---|
1789 | int |
---|
1790 | rpack() { |
---|
1791 | register int i, j, x, lp; /* Local variables */ |
---|
1792 | int k, type, chklen; |
---|
1793 | unsigned crc; |
---|
1794 | CHAR pbc[4]; /* Packet block check */ |
---|
1795 | CHAR *sohp; /* Pointer to SOH */ |
---|
1796 | CHAR e; /* Packet end character */ |
---|
1797 | |
---|
1798 | #ifdef GETMSEC |
---|
1799 | long t1, t2; |
---|
1800 | #endif /* GETMSEC */ |
---|
1801 | |
---|
1802 | debug(F101,"entering rpack, pktnum","",pktnum); |
---|
1803 | |
---|
1804 | #ifndef OLDCHKINT |
---|
1805 | if (chkint() < 0) /* Check for console interrupts. */ |
---|
1806 | return('z'); |
---|
1807 | #endif /* OLDCHKINT */ |
---|
1808 | |
---|
1809 | k = getrbuf(); /* Get a new packet input buffer. */ |
---|
1810 | debug(F101,"rpack getrbuf","",k); |
---|
1811 | if (k < 0) return(-1); /* Return like this if none free. */ |
---|
1812 | if (pktmsg) *pktmsg = NUL; |
---|
1813 | recpkt = r_pkt[k].bf_adr; |
---|
1814 | *recpkt = '\0'; /* Clear receive buffer. */ |
---|
1815 | sohp = recpkt; /* Initialize pointers to it. */ |
---|
1816 | rdatap = recpkt; |
---|
1817 | rsn = rln = -1; /* In case of failure. */ |
---|
1818 | e = (turn) ? turnch : eol; /* Use any handshake char for eol */ |
---|
1819 | |
---|
1820 | /* Try to get a "line". */ |
---|
1821 | |
---|
1822 | #ifdef GETMSEC |
---|
1823 | if (deblog) t1 = getmsec(); |
---|
1824 | #endif /* GETMSEC */ |
---|
1825 | |
---|
1826 | #ifdef PARSENSE |
---|
1827 | #ifdef UNIX |
---|
1828 | /* |
---|
1829 | So far the final turn argument is only for ck[uvdl]tio.c. Should be added |
---|
1830 | to the others too. (turn == handshake character.) |
---|
1831 | */ |
---|
1832 | j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn); |
---|
1833 | #else |
---|
1834 | #ifdef VMS |
---|
1835 | j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn); |
---|
1836 | #else |
---|
1837 | #ifdef datageneral |
---|
1838 | j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn); |
---|
1839 | #else |
---|
1840 | #ifdef STRATUS |
---|
1841 | j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn); |
---|
1842 | #else |
---|
1843 | #ifdef OS2 |
---|
1844 | j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn); |
---|
1845 | #else |
---|
1846 | #ifdef OSK |
---|
1847 | j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn); |
---|
1848 | #else |
---|
1849 | j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr); |
---|
1850 | #endif /* OSK */ |
---|
1851 | #endif /* OS2 */ |
---|
1852 | #endif /* STRATUS */ |
---|
1853 | #endif /* datageneral */ |
---|
1854 | #endif /* VMS */ |
---|
1855 | #endif /* UNIX */ |
---|
1856 | if (parity != ttprty) autopar = 1; |
---|
1857 | parity = ttprty; |
---|
1858 | #else /* !PARSENSE */ |
---|
1859 | j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e); |
---|
1860 | #endif /* PARSENSE */ |
---|
1861 | |
---|
1862 | #ifdef GETMSEC |
---|
1863 | if (deblog) { |
---|
1864 | t2 = getmsec(); |
---|
1865 | if (t2 > -1L && t1 > -1L) |
---|
1866 | debug(F101,"rpack ttinl time","",t2-t1); |
---|
1867 | else |
---|
1868 | debug(F100,"rpack ttinl time error","",0); |
---|
1869 | } |
---|
1870 | #endif /* GETMSEC */ |
---|
1871 | |
---|
1872 | if (j < 0) { |
---|
1873 | debug(F101,"rpack: ttinl fails","",j); /* Otherwise, */ |
---|
1874 | freerbuf(k); /* Free this buffer */ |
---|
1875 | if (j < -1) { /* Bail out if ^C^C typed. */ |
---|
1876 | debug(F101,"rpack ^C server","",server); |
---|
1877 | debug(F101,"rpack ^C en_fin","",en_fin); |
---|
1878 | if (server == 0) return(j); /* But not if in server mode */ |
---|
1879 | else if (en_fin) return(j); /* with DISABLE FINISH */ |
---|
1880 | else return(-2); |
---|
1881 | } |
---|
1882 | if (nakstate) /* Call it a timeout. */ |
---|
1883 | screen(SCR_PT,'T',(long)winlo,""); |
---|
1884 | else |
---|
1885 | screen(SCR_PT,'T',(long)pktnum,""); |
---|
1886 | logpkt('r',-1,(CHAR *)"<timeout>"); |
---|
1887 | if (flow == 1) ttoc(XON); /* In case of Xoff blockage. */ |
---|
1888 | return('T'); |
---|
1889 | } |
---|
1890 | rpktl = j; |
---|
1891 | tlci += j; /* All OK, Count the characters. */ |
---|
1892 | flci += j; |
---|
1893 | |
---|
1894 | #ifndef PARSENSE |
---|
1895 | /* THEN eliminate this loop... */ |
---|
1896 | for (i = 0; (recpkt[i] != stchr) && (i < j); i++) |
---|
1897 | sohp++; /* Find mark */ |
---|
1898 | if (i++ >= j) { /* Didn't find it. */ |
---|
1899 | logpkt('r',-1,"<timeout>"); |
---|
1900 | freerbuf(k); |
---|
1901 | return('T'); |
---|
1902 | } |
---|
1903 | #else |
---|
1904 | i = 1; |
---|
1905 | #endif /* PARSENSE */ |
---|
1906 | |
---|
1907 | rpackets++; |
---|
1908 | lp = i; /* Remember LEN position. */ |
---|
1909 | if ((j = xunchar(recpkt[i++])) == 0) { |
---|
1910 | if ((j = lp+5) > MAXRP) return('Q'); /* Long packet */ |
---|
1911 | x = recpkt[j]; /* Header checksum. */ |
---|
1912 | recpkt[j] = '\0'; /* Calculate & compare. */ |
---|
1913 | if (xunchar(x) != chk1(recpkt+lp)) { |
---|
1914 | freerbuf(k); |
---|
1915 | logpkt('r',-1,(CHAR *)"<crunched:hdr>"); |
---|
1916 | screen(SCR_PT,'%',(long)pktnum,"Bad packet header"); |
---|
1917 | return('Q'); |
---|
1918 | } |
---|
1919 | recpkt[j] = x; /* Checksum ok, put it back. */ |
---|
1920 | rln = xunchar(recpkt[j-2]) * 95 + xunchar(recpkt[j-1]) - bctl; |
---|
1921 | j = 3; /* Data offset. */ |
---|
1922 | } else if (j < 3) { |
---|
1923 | debug(F101,"rpack packet length less than 3","",j); |
---|
1924 | freerbuf(k); |
---|
1925 | logpkt('r',-1,(CHAR *)"<crunched:len>"); |
---|
1926 | screen(SCR_PT,'%',(long)pktnum,"Bad packet length"); |
---|
1927 | return('Q'); |
---|
1928 | } else { |
---|
1929 | rln = j - bctl - 2; /* Regular packet */ |
---|
1930 | j = 0; /* No extended header */ |
---|
1931 | } |
---|
1932 | rsn = xunchar(recpkt[i++]); /* Sequence number */ |
---|
1933 | logpkt('r',rsn,sohp); |
---|
1934 | if (rsn < 0 || rsn > 63) { |
---|
1935 | debug(F101,"rpack bad sequence number","",rsn); |
---|
1936 | freerbuf(k); |
---|
1937 | logpkt('r',rsn,(CHAR *)"<crunched:seq>"); |
---|
1938 | screen(SCR_PT,'%',(long)pktnum,"Bad sequence number"); |
---|
1939 | return('Q'); |
---|
1940 | } |
---|
1941 | /* |
---|
1942 | If this packet has the same type as the packet just sent, assume it is |
---|
1943 | an echo and ignore it. Don't even bother with the block check calculation: |
---|
1944 | even if the packet is corrupted, we don't want to NAK an echoed packet. |
---|
1945 | (And we certainly don't want to NAK an ACK or NAK!) |
---|
1946 | */ |
---|
1947 | type = recpkt[i++]; /* Get packet's TYPE field */ |
---|
1948 | if (type == sndtyp || (nakstate && (type == 'N' /* || type == 'Y' */ ))) { |
---|
1949 | debug(F000,"rpack echo","",type); /* If it's an echo */ |
---|
1950 | freerbuf(k); /* Free this buffer */ |
---|
1951 | logpkt('#',rsn,(CHAR *)"<echo:ignored>"); |
---|
1952 | return('e'); /* return special (lowercase) code */ |
---|
1953 | } |
---|
1954 | /* |
---|
1955 | Separate the data from the block check, accounting for the case where |
---|
1956 | a packet was retransmitted after the block check switched. |
---|
1957 | */ |
---|
1958 | if (type == 'I' || type == 'S') { /* I & S packets always have type 1 */ |
---|
1959 | chklen = 1; |
---|
1960 | rln = rln + bctl - 1; |
---|
1961 | } else if (type == 'N') { /* A NAK packet never has data */ |
---|
1962 | chklen = xunchar(recpkt[lp]) - 2; |
---|
1963 | rln = rln + bctl - chklen; |
---|
1964 | } else chklen = bctl; |
---|
1965 | debug(F101,"rpack bctl","",bctl); |
---|
1966 | debug(F101,"rpack chklen","",chklen); |
---|
1967 | |
---|
1968 | i += j; /* Buffer index of DATA field */ |
---|
1969 | rdatap = recpkt+i; /* Pointer to DATA field */ |
---|
1970 | if ((j = rln + i) > r_pkt[k].bf_len ) { /* Make sure it fits */ |
---|
1971 | debug(F101,"packet sticks out too far","",j); |
---|
1972 | freerbuf(k); |
---|
1973 | logpkt('r',rsn,(CHAR *)"<overflow>"); |
---|
1974 | return('Q'); |
---|
1975 | } |
---|
1976 | |
---|
1977 | for (x = 0; x < chklen; x++) /* Copy the block check */ |
---|
1978 | pbc[x] = recpkt[j+x]; |
---|
1979 | pbc[x] = '\0'; /* Null-terminate block check string */ |
---|
1980 | recpkt[j] = '\0'; /* and the packet DATA field. */ |
---|
1981 | |
---|
1982 | if (chklen == 2 && bctu == 4) { /* Adjust for Blank-Free-2 */ |
---|
1983 | chklen = 4; /* (chklen is now a misnomer...) */ |
---|
1984 | debug(F100,"rpack block check B","",0); |
---|
1985 | } |
---|
1986 | switch (chklen) { /* Check the block check */ |
---|
1987 | case 1: /* Type 1, 6-bit checksum */ |
---|
1988 | if (xunchar(*pbc) != chk1(recpkt+lp)) { |
---|
1989 | debug(F110,"checked chars",recpkt+lp,0); |
---|
1990 | debug(F101,"block check","",(int) xunchar(*pbc)); |
---|
1991 | debug(F101,"should be","",chk1(recpkt+lp)); |
---|
1992 | freerbuf(k); |
---|
1993 | logpkt('r',-1,(CHAR *)"<crunched:chk1>"); |
---|
1994 | screen(SCR_PT,'%',(long)pktnum,"Checksum error"); |
---|
1995 | return('Q'); |
---|
1996 | } |
---|
1997 | break; |
---|
1998 | case 2: /* Type 2, 12-bit checksum */ |
---|
1999 | x = xunchar(*pbc) << 6 | xunchar(pbc[1]); |
---|
2000 | if (x != chk2(recpkt+lp)) { /* No match */ |
---|
2001 | if (type == 'E') { /* Allow E packets to have type 1 */ |
---|
2002 | recpkt[j++] = pbc[0]; |
---|
2003 | recpkt[j] = '\0'; |
---|
2004 | if (xunchar(pbc[1]) == chk1(recpkt+lp)) |
---|
2005 | break; |
---|
2006 | else |
---|
2007 | recpkt[--j] = '\0'; |
---|
2008 | } |
---|
2009 | debug(F110,"checked chars",recpkt+lp,0); |
---|
2010 | debug(F101,"block check","", x); |
---|
2011 | debug(F101,"should be","", (int) chk2(recpkt+lp)); |
---|
2012 | freerbuf(k); |
---|
2013 | logpkt('r',-1,(CHAR *)"<crunched:chk2>"); |
---|
2014 | screen(SCR_PT,'%',(long)pktnum,"Checksum error"); |
---|
2015 | return('Q'); |
---|
2016 | } |
---|
2017 | break; |
---|
2018 | case 3: /* Type 3, 16-bit CRC */ |
---|
2019 | crc = (xunchar(pbc[0]) << 12) |
---|
2020 | | (xunchar(pbc[1]) << 6) |
---|
2021 | | (xunchar(pbc[2])); |
---|
2022 | if (crc != chk3(recpkt+lp,parity)) { |
---|
2023 | if (type == 'E') { /* Allow E packets to have type 1 */ |
---|
2024 | recpkt[j++] = pbc[0]; |
---|
2025 | recpkt[j++] = pbc[1]; |
---|
2026 | recpkt[j] = '\0'; |
---|
2027 | if (xunchar(pbc[2]) == chk1(recpkt+lp)) |
---|
2028 | break; |
---|
2029 | else { j -=2; recpkt[j] = '\0'; } |
---|
2030 | } |
---|
2031 | debug(F110,"checked chars",recpkt+lp,0); |
---|
2032 | debug(F101,"block check","",xunchar(*pbc)); |
---|
2033 | debug(F101,"should be","",(int) chk3(recpkt+lp,parity)); |
---|
2034 | freerbuf(k); |
---|
2035 | logpkt('r',-1,(CHAR *)"<crunched:chk3>"); |
---|
2036 | screen(SCR_PT,'%',(long)pktnum,"CRC error"); |
---|
2037 | return('Q'); |
---|
2038 | } |
---|
2039 | break; |
---|
2040 | case 4: /* Type 4 = Type 2, no blanks. */ |
---|
2041 | x = (unsigned)((xunchar(*pbc) - 1) << 6) | |
---|
2042 | (unsigned)(xunchar(pbc[1]) - 1); |
---|
2043 | if (x != chk2(recpkt+lp)) { |
---|
2044 | if (type == 'E') { /* Allow E packets to have type 1 */ |
---|
2045 | recpkt[j++] = pbc[0]; |
---|
2046 | recpkt[j] = '\0'; |
---|
2047 | if (xunchar(pbc[1]) == chk1(recpkt+lp)) |
---|
2048 | break; |
---|
2049 | else |
---|
2050 | recpkt[--j] = '\0'; |
---|
2051 | } |
---|
2052 | debug(F101,"bad type B block check","",x); |
---|
2053 | freerbuf(k); |
---|
2054 | logpkt('r',-1,(CHAR *)"<crunched:chkb>"); |
---|
2055 | screen(SCR_PT,'%',(long)pktnum,"Checksum error"); |
---|
2056 | return('Q'); |
---|
2057 | } |
---|
2058 | break; |
---|
2059 | default: /* Shouldn't happen... */ |
---|
2060 | freerbuf(k); |
---|
2061 | logpkt('r',-1,(CHAR *)"<crunched:chkx>"); |
---|
2062 | screen(SCR_PT,'%',(long)pktnum,"(crunched)"); |
---|
2063 | return('Q'); |
---|
2064 | } |
---|
2065 | debug(F101,"rpack block check OK","",rsn); |
---|
2066 | |
---|
2067 | /* Now we can believe the sequence number, and other fields. */ |
---|
2068 | /* Here we violate strict principles of layering, etc, and look at the */ |
---|
2069 | /* packet sequence number. If there's already a packet with the same */ |
---|
2070 | /* number in the window, we remove this one so that the window will not */ |
---|
2071 | /* fill up. */ |
---|
2072 | |
---|
2073 | if ((x = rseqtbl[rsn]) != -1) { /* Already a packet with this number */ |
---|
2074 | retrans++; /* Count it for statistics */ |
---|
2075 | debug(F101,"rpack got dup","",rsn); |
---|
2076 | logpkt('r',rsn,(CHAR *)"<duplicate>"); |
---|
2077 | freerbuf(x); /* Free old buffer, keep new packet. */ |
---|
2078 | r_pkt[k].pk_rtr++; /* Count this as a retransmission. */ |
---|
2079 | } |
---|
2080 | |
---|
2081 | /* New packet, not seen before, enter it into the receive window. */ |
---|
2082 | |
---|
2083 | #ifdef CK_TIMERS |
---|
2084 | rrttbl[rsn] = gtimer(); /* Timestamp */ |
---|
2085 | #endif /* CK_TIMERS */ |
---|
2086 | |
---|
2087 | rseqtbl[rsn] = k; /* Make back pointer */ |
---|
2088 | r_pkt[k].pk_seq = rsn; /* Record in packet info structure */ |
---|
2089 | r_pkt[k].pk_typ = type; /* Sequence, type,... */ |
---|
2090 | r_pkt[k].pk_adr = rdatap; /* pointer to data buffer */ |
---|
2091 | screen(SCR_PT,(char)type,(long)rsn,(char *)sohp); /* Update screen */ |
---|
2092 | return(type); /* Return packet type */ |
---|
2093 | } |
---|
2094 | |
---|
2095 | /* L O G P K T -- Log packet number n, pointed to by s. */ |
---|
2096 | |
---|
2097 | /* c = 's' (send) or 'r' (receive) */ |
---|
2098 | |
---|
2099 | VOID |
---|
2100 | #ifdef CK_ANSIC |
---|
2101 | logpkt(char c,int n, CHAR *s) |
---|
2102 | #else |
---|
2103 | logpkt(c,n,s) char c; int n; CHAR *s; |
---|
2104 | #endif /* CK_ANSIC */ |
---|
2105 | /* logpkt */ { |
---|
2106 | char plog[20]; |
---|
2107 | if (pktlog && *s) { |
---|
2108 | if (n < 0) |
---|
2109 | sprintf(plog,"%c-xx-%02d-",c,(gtimer()%60)); |
---|
2110 | else |
---|
2111 | sprintf(plog,"%c-%02d-%02d-",c,n,(gtimer()%60)); |
---|
2112 | if (zsout(ZPFILE,plog) < 0) pktlog = 0; |
---|
2113 | else if (zsoutl(ZPFILE,(char *)s) < 0) pktlog = 0; |
---|
2114 | } |
---|
2115 | } |
---|
2116 | |
---|
2117 | #ifdef TLOG |
---|
2118 | |
---|
2119 | /* T S T A T S -- Record statistics in transaction log */ |
---|
2120 | |
---|
2121 | VOID |
---|
2122 | tstats() { |
---|
2123 | char *tp; |
---|
2124 | ztime(&tp); /* Get time stamp */ |
---|
2125 | tlog(F100,"","",0L); /* Leave a blank line */ |
---|
2126 | tlog(F110,"Transaction complete",tp,0L); /* Record it */ |
---|
2127 | |
---|
2128 | if (filcnt < 1) return; /* If no files, done. */ |
---|
2129 | |
---|
2130 | /* If multiple files, record character totals for all files */ |
---|
2131 | |
---|
2132 | if (filcnt > 1) { |
---|
2133 | tlog(F101," files transferred ","",filcnt - filrej); |
---|
2134 | tlog(F101," total file characters ","",tfc); |
---|
2135 | tlog(F101," communication line in ","",tlci); |
---|
2136 | tlog(F101," communication line out ","",tlco); |
---|
2137 | } |
---|
2138 | |
---|
2139 | /* Record timing info for one or more files */ |
---|
2140 | |
---|
2141 | tlog(F101," elapsed time (seconds) ","",(long) tsecs); |
---|
2142 | if (tsecs > 0) { |
---|
2143 | long lx; |
---|
2144 | lx = (tfc * 10L) / (long) tsecs; |
---|
2145 | tlog(F101," effective data rate ","",lx/10L); |
---|
2146 | if (speed <= 0L) speed = ttgspd(); |
---|
2147 | #ifdef COMMENT |
---|
2148 | if (speed > 0L && speed != 8880L && network == 0) { |
---|
2149 | lx = (lx * 100L) / speed; |
---|
2150 | tlog(F101," efficiency (percent) ","",lx); |
---|
2151 | } |
---|
2152 | #endif /* COMMENT */ |
---|
2153 | } |
---|
2154 | tlog(F100,"","",0L); /* Leave a blank line */ |
---|
2155 | } |
---|
2156 | |
---|
2157 | /* F S T A T S -- Record file statistics in transaction log */ |
---|
2158 | |
---|
2159 | VOID |
---|
2160 | fstats() { |
---|
2161 | tfc += ffc; |
---|
2162 | if (!discard && !cxseen && !czseen && what != W_NOTHING) |
---|
2163 | tlog(F101," complete, size","",ffc); |
---|
2164 | } |
---|
2165 | #else /* NOTLOG */ |
---|
2166 | VOID |
---|
2167 | tstats() {} |
---|
2168 | |
---|
2169 | VOID |
---|
2170 | fstats() { |
---|
2171 | tfc += ffc; |
---|
2172 | } |
---|
2173 | #endif /* TLOG */ |
---|