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, 2002, |
---|
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 |
---|
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, bctl, rsn, rln, maxtry, size; |
---|
223 | extern int 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, ffc, flci, flco, tlci, tlco, tfc, speed; |
---|
235 | extern long filcps, tfcps; |
---|
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 |
---|
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 |
---|
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 |
---|
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 | #endif /* CK_TIMERS */ |
---|
700 | debug(F101,"input rsn=winlo","",rsn); |
---|
701 | break; |
---|
702 | } |
---|
703 | |
---|
704 | /* Got a packet out of order. */ |
---|
705 | |
---|
706 | debug(F101,"input out of sequence, rsn","",rsn); |
---|
707 | k = rseqtbl[rsn]; /* Get window slot of this packet. */ |
---|
708 | debug(F101,"input rseqtbl[rsn]","",k); |
---|
709 | if (k < 0) { |
---|
710 | debug(F101,"input recv can't find index for rcvd pkt","",rsn); |
---|
711 | /* Was "Internal error 21" */ |
---|
712 | /* This should not happen */ |
---|
713 | errpkt((CHAR *)"Sliding windows protocol error."); |
---|
714 | type = 'E'; |
---|
715 | break; |
---|
716 | } |
---|
717 | y = chkwin(rsn,winlo,wslots); /* See what window it's in. */ |
---|
718 | debug(F101,"input recv chkwin","",y); |
---|
719 | if (y == 1) { /* From previous window. */ |
---|
720 | #ifdef STREAMING |
---|
721 | if (!streaming) /* NO RESEND IF STREAMING! */ |
---|
722 | #endif /* STREAMING */ |
---|
723 | resend(rsn); /* Resend the ACK (might have data) */ |
---|
724 | freerpkt(rsn); /* Get rid of received packet */ |
---|
725 | continue; /* Back to wait for another packet */ |
---|
726 | } else { /* In this window or out of range */ |
---|
727 | if (y < 0) /* If out of range entirely, */ |
---|
728 | freerpkt(rsn); /* release its buffer */ |
---|
729 | |
---|
730 | #ifdef STREAMING |
---|
731 | if (streaming) { /* Streaming (this shouldn't happen) */ |
---|
732 | errpkt((CHAR *)"Sequence error on reliable link."); |
---|
733 | type = 'E'; |
---|
734 | break; |
---|
735 | } |
---|
736 | #endif /* STREAMING */ |
---|
737 | |
---|
738 | /* If our receive window is full, NAK window-low */ |
---|
739 | |
---|
740 | if (rbufnum < 1) { /* Receive window full? */ |
---|
741 | if (nack(winlo) < 0) { /* No choice, must NAK winlo. */ |
---|
742 | errpkt((CHAR *)"Too many retries."); /* Too many */ |
---|
743 | type = 'E'; |
---|
744 | break; |
---|
745 | } else continue; |
---|
746 | } |
---|
747 | /* |
---|
748 | Receive window not full. This is a packet in the current window but it is |
---|
749 | not the desired packet at winlo. So therefore there are gaps before this |
---|
750 | packet. So we find the "lowest" unNAK'd missing packet, if any, between |
---|
751 | winlo and this one, and NAK it. If there are no as-yet-unNAK'd missing |
---|
752 | packets in the window, then we send nothing and go wait for another packet. |
---|
753 | In theory, this could result in a timeout, but in practice it is likely that |
---|
754 | the already-NAK'd missing packets are already on their way. Note, we do not |
---|
755 | NAK ahead of ourselves, as that only creates unnecessary retransmissions. |
---|
756 | */ |
---|
757 | for (x = winlo; x != rsn; x = (x + 1) % 64) { |
---|
758 | if (rseqtbl[x] > -1) /* Have I received packet x? */ |
---|
759 | continue; /* Yes, check next sequence number. */ |
---|
760 | pi = sseqtbl[x]; /* No, have I NAK'd it yet? */ |
---|
761 | if (pi < 0 || s_pkt[pi].pk_rtr == 0) { |
---|
762 | nack(x); /* No, NAK it now. */ |
---|
763 | break; |
---|
764 | } |
---|
765 | } |
---|
766 | } |
---|
767 | /*!!!*/ |
---|
768 | } else { /* Otherwise file sender... */ |
---|
769 | |
---|
770 | #ifdef STREAMING |
---|
771 | if (streaming && sndtyp == 'D') { |
---|
772 | debug(F101,"STREAMING input streaming","",streaming); |
---|
773 | debug(F000,"STREAMING input sndtyp","",sndtyp); |
---|
774 | rsn = winlo; |
---|
775 | type = 'Y'; /* Pretend we got an ACK */ |
---|
776 | } |
---|
777 | #endif /* STREAMING */ |
---|
778 | if (!nak2ack) { /* NAK(n+1) = ACK(n) */ |
---|
779 | if (wslots > 1) { /* Packet at winlo already ACK'd? */ |
---|
780 | if (sacktbl[winlo]) { /* If so, */ |
---|
781 | sacktbl[winlo] = 0; /* Turn off the ACK'd flag */ |
---|
782 | winlo = (winlo + 1) % 64; /* Rotate the window */ |
---|
783 | type = 'Y'; /* And return ACK */ |
---|
784 | debug(F101, |
---|
785 | "input send returning pre-stashed ACK","", |
---|
786 | winlo-1); |
---|
787 | break; |
---|
788 | } |
---|
789 | } |
---|
790 | #ifdef STREAMING |
---|
791 | if (!(streaming && sndtyp == 'D')) { /* Not streaming | data */ |
---|
792 | type = rpack(); /* Try to read an acknowledgement */ |
---|
793 | } else { /* Streaming and in Data phase */ |
---|
794 | type = 'Y'; /* Assume all is normal */ |
---|
795 | if (chkint() < 0) /* Check for console interrupts. */ |
---|
796 | type = 'z'; |
---|
797 | else if (ttchk() > 4 + bctu) /* Check for return traffic */ |
---|
798 | type = rpack(); |
---|
799 | debug(F000,"input streaming type","",type); |
---|
800 | } |
---|
801 | #endif /* STREAMING */ |
---|
802 | debug(F111,"input send",(char *) rdatap,(int) type); |
---|
803 | while (type == 'e') { /* Handle echoes */ |
---|
804 | debug(F000,"echo discarded","",type); |
---|
805 | type = rpack(); |
---|
806 | } |
---|
807 | #ifndef OLDCHKINT |
---|
808 | if (type == 'z') { |
---|
809 | epktrcvd = 1; |
---|
810 | errpkt((CHAR *)"User cancelled."); |
---|
811 | type = 'E'; |
---|
812 | break; |
---|
813 | } |
---|
814 | #endif /* OLDCHKINT */ |
---|
815 | if (type < -1) { |
---|
816 | xxscreen(SCR_PT,'q',0L, |
---|
817 | ((char *)((type == -2) ? |
---|
818 | "Interrupted" : |
---|
819 | "Connection lost")) |
---|
820 | ); |
---|
821 | if (type != -2) |
---|
822 | dologend(); |
---|
823 | return('q'); /* Ctrl-C or connection lost */ |
---|
824 | } |
---|
825 | if (type == -1) { |
---|
826 | #ifdef COMMENT |
---|
827 | char foo[256]; |
---|
828 | ckmakxmsg(foo,256, |
---|
829 | "Receive window full (error 18): wslots=", |
---|
830 | ckitoa(wslots), |
---|
831 | " winlo=",ckitoa(winlo)," pktnum=", |
---|
832 | ckitoa(pktnum), NULL,NULL,NULL,NULL,NULL,NULL); |
---|
833 | errpkt((CHAR *)foo); |
---|
834 | debug(F100,foo,"",0); |
---|
835 | #else |
---|
836 | errpkt((CHAR *)"Receive window full"); /* was "internal */ |
---|
837 | debug(F101," wslots","",wslots); /* error 18" */ |
---|
838 | debug(F101," winlo","",winlo); |
---|
839 | debug(F101," pktnum","",pktnum); |
---|
840 | #endif /* COMMENT */ |
---|
841 | dumprbuf(); |
---|
842 | type = 'E'; |
---|
843 | break; |
---|
844 | } |
---|
845 | dumprbuf(); /* Debugging */ |
---|
846 | |
---|
847 | #ifdef OLDCHKINT |
---|
848 | if (chkint() < 0) { /* Check for console interrupts. */ |
---|
849 | errpkt((CHAR *)"User cancelled."); |
---|
850 | return(type = 'E'); |
---|
851 | } |
---|
852 | #endif /* OLDCHKINT */ |
---|
853 | |
---|
854 | /* Got a packet */ |
---|
855 | |
---|
856 | #ifdef STREAMING |
---|
857 | if (streaming) { /* Streaming */ |
---|
858 | if (type == 'Q' || type == 'T') { /* Errors are fatal. */ |
---|
859 | crunched++; /* For statistics */ |
---|
860 | errpkt((CHAR *)"Transmission error on reliable link."); |
---|
861 | type = 'E'; |
---|
862 | } |
---|
863 | } |
---|
864 | #endif /* STREAMING */ |
---|
865 | if (type == 'E') { |
---|
866 | debug(F101,"input send got E, nakstate","",nakstate); |
---|
867 | break; /* Error packet */ |
---|
868 | } |
---|
869 | if (type == 'Q') { /* Crunched packet */ |
---|
870 | crunched++; /* For statistics */ |
---|
871 | numerrs++; /* For packet resizing */ |
---|
872 | x = resend(winlo); /* Resend window-low */ |
---|
873 | if (x < 0) { |
---|
874 | type = 'E'; |
---|
875 | errpkt((CHAR *)"Too many retries"); |
---|
876 | break; |
---|
877 | } |
---|
878 | continue; |
---|
879 | } |
---|
880 | if (type == 'T') { /* Timeout waiting for ACKs. */ |
---|
881 | timeouts++; /* Count it */ |
---|
882 | numerrs++; /* Count an error too */ |
---|
883 | debug(F101,"input send state timeout, winlo","",winlo); |
---|
884 | |
---|
885 | /* Retransmit the oldest un-ACK'd packet. */ |
---|
886 | |
---|
887 | debug(F101,"input send resending winlo","",winlo); |
---|
888 | if (resend(winlo) < 0) { /* Check retries */ |
---|
889 | debug(F101,"input send too many resends","",maxtry); |
---|
890 | errpkt((CHAR *)"Too many retries"); |
---|
891 | return(type = 'E'); |
---|
892 | } |
---|
893 | #ifdef NEWDPL |
---|
894 | /* Reduce prevailing packet length */ |
---|
895 | x = sseqtbl[winlo]; /* Get length of packet we want ACKd */ |
---|
896 | if (x > -1) { /* Only if we have a valid index */ |
---|
897 | if (s_pkt[x].pk_typ == 'D') { /* only for D packets */ |
---|
898 | spsiz = (s_pkt[x].pk_len + 8) >> 1; /* halve it */ |
---|
899 | if (spsiz < 20) spsiz = 20; /* within reason */ |
---|
900 | debug(F101,"input T cut packet length","",spsiz); |
---|
901 | } |
---|
902 | } |
---|
903 | #endif /* NEWDPL */ |
---|
904 | continue; |
---|
905 | } |
---|
906 | } |
---|
907 | /* Got an actual normal packet */ |
---|
908 | |
---|
909 | nak2ack = 0; /* Unset this flag. */ |
---|
910 | y = chkwin(rsn,winlo,wslots); /* Is it in the window? */ |
---|
911 | debug(F101,"input send rsn","",rsn); |
---|
912 | debug(F101,"input send winlo","",winlo); |
---|
913 | debug(F101,"input send chkwin","",y); |
---|
914 | |
---|
915 | if (type == 'Y') { /* Got an ACK */ |
---|
916 | if (y == 0) { /* In current window */ |
---|
917 | if (spackets < 4) /* Error counter doesn't count */ |
---|
918 | numerrs = 0; /* until data phase. */ |
---|
919 | sacktbl[rsn]++; /* Mark the packet as ACK'd */ |
---|
920 | x = sseqtbl[rsn]; /* Get ACK'd packet's buffer index */ |
---|
921 | debug(F101,"bestlen ack x","",x); |
---|
922 | #ifdef NEWDPL |
---|
923 | if (x > -1) { |
---|
924 | acktype = s_pkt[x].pk_typ; /* Get type */ |
---|
925 | debug(F000,"bestlen ack type","",acktype); |
---|
926 | |
---|
927 | if (acktype == 'D') { /* Adjust data packet length */ |
---|
928 | if (spsiz > bestlen) { |
---|
929 | bestlen = spsiz; |
---|
930 | debug(F101,"bestlen B","",bestlen); |
---|
931 | } |
---|
932 | #ifdef DEBUG |
---|
933 | if (deblog) { |
---|
934 | debug(F101,"bestlen retry","",s_pkt[x].pk_rtr); |
---|
935 | debug(F101,"bestlen len","",s_pkt[x].pk_len); |
---|
936 | debug(F101,"bestlen spackets","",spackets); |
---|
937 | } |
---|
938 | #endif /* DEBUG */ |
---|
939 | /* Set new best length */ |
---|
940 | if (s_pkt[x].pk_rtr == 0 && |
---|
941 | s_pkt[x].pk_len + 8 > bestlen) { |
---|
942 | bestlen = s_pkt[x].pk_len + 8; |
---|
943 | if (bestlen > spmax) |
---|
944 | bestlen = spmax; |
---|
945 | debug(F101,"bestlen A","",bestlen); |
---|
946 | } |
---|
947 | #ifdef DEBUG |
---|
948 | if (deblog) { |
---|
949 | debug(F101,"bestlen wslots","",wslots); |
---|
950 | debug(F101,"bestlen maxsend","",maxsend); |
---|
951 | } |
---|
952 | #endif /* DEBUG */ |
---|
953 | /* Slow start */ |
---|
954 | if (slostart && |
---|
955 | (maxsend <= spmax) && |
---|
956 | (rpackets < 11) && |
---|
957 | (numerrs == 0)) { |
---|
958 | spsiz = spsiz << 1; |
---|
959 | debug(F101,"bestlen spsiz A","",spsiz); |
---|
960 | |
---|
961 | /* Creep up to best length */ |
---|
962 | } else if ((spackets > 5) && |
---|
963 | (spsiz < bestlen - 8)) { |
---|
964 | spsiz += (bestlen - spsiz) / 3; |
---|
965 | debug(F101,"bestlen spsiz B","",spsiz); |
---|
966 | |
---|
967 | /* Push the envelope */ |
---|
968 | } else if ((spackets % (wslots + 1) == 0) && |
---|
969 | (spackets > 6) && |
---|
970 | (bestlen < spmax - 8) && |
---|
971 | (spsiz < spmax)) { |
---|
972 | spsiz += (spmax - bestlen) / 3; |
---|
973 | debug(F101,"bestlen spsiz C","",spsiz); |
---|
974 | } |
---|
975 | /* But not too far */ |
---|
976 | if (spsiz > spmax) { |
---|
977 | spsiz = spmax; |
---|
978 | debug(F101,"bestlen spsiz D","",spsiz); |
---|
979 | } |
---|
980 | } |
---|
981 | } |
---|
982 | #endif /* NEWDPL */ |
---|
983 | |
---|
984 | #ifdef CK_TIMERS |
---|
985 | if (rttflg && timint) /* If doing dynamic timers */ |
---|
986 | getrtt(nakstate, rsn); /* call routine to set it. */ |
---|
987 | #endif /* CK_TIMERS */ |
---|
988 | /* |
---|
989 | NOTE: The following statement frees the buffer of the ACK we just got. |
---|
990 | But the upper layers still need the data, like if it's the ACK to an I, |
---|
991 | S, F, D, Z, or just about any kind of packet. So for now, freerbuf() |
---|
992 | deallocates the buffer, but does not erase the data or destroy the pointer |
---|
993 | to it. There's no other single place where these receive buffers can be |
---|
994 | correctly freed (?) ... |
---|
995 | */ |
---|
996 | freerpkt(rsn); /* Free the ACK's buffer */ |
---|
997 | freesbuf(rsn); /* *** Free the sent packet's buffer */ |
---|
998 | if (rsn == winlo) { /* Got the one we want */ |
---|
999 | sacktbl[winlo] = 0; |
---|
1000 | winlo = (winlo + 1) % 64; |
---|
1001 | debug(F101,"input send rotated send window","",winlo); |
---|
1002 | break; /* Return the ACK */ |
---|
1003 | } else { |
---|
1004 | debug(F101,"input send mark pkt","",rsn); |
---|
1005 | continue; /* Otherwise go read another packet */ |
---|
1006 | } |
---|
1007 | } else if (y == 1 && wslots < 2) { /* (190) ACK for previous */ |
---|
1008 | numerrs++; /* == NAK for current, count error */ |
---|
1009 | debug(F101,"input send ACK for previous","",rsn); |
---|
1010 | freerpkt(rsn); /* Free NAK's buffer */ |
---|
1011 | x = resend(winlo); /* Resend current packet */ |
---|
1012 | if (x < 0) { |
---|
1013 | type = 'E'; |
---|
1014 | errpkt((CHAR *)"Too many retries"); |
---|
1015 | break; |
---|
1016 | } else continue; /* Resend ok, go read another packet */ |
---|
1017 | } else { /* Other cases, just ignore */ |
---|
1018 | debug(F101,"input send ACK out of window","",rsn); |
---|
1019 | freerpkt(rsn); |
---|
1020 | continue; |
---|
1021 | } |
---|
1022 | } |
---|
1023 | if (type == 'N') { /* NAK */ |
---|
1024 | numerrs++; /* Count an error */ |
---|
1025 | #ifdef STREAMING |
---|
1026 | if (streaming) { /* Streaming */ |
---|
1027 | errpkt((CHAR *)"NAK received on reliable link."); |
---|
1028 | type = 'E'; |
---|
1029 | break; |
---|
1030 | } |
---|
1031 | #endif /* STREAMING */ |
---|
1032 | |
---|
1033 | debug(F101,"input send NAK","",rsn); |
---|
1034 | #ifdef NEWDPL |
---|
1035 | /* Reduce prevailing packet length */ |
---|
1036 | x = sseqtbl[rsn]; /* Length of packet that was NAK'd */ |
---|
1037 | if (x > -1) { /* If it's a Data packet we've sent */ |
---|
1038 | if (s_pkt[x].pk_typ == 'D') { |
---|
1039 | spsiz = (s_pkt[x].pk_len + 8) >> 1; /* Halve length */ |
---|
1040 | #ifdef COMMENT |
---|
1041 | /* This might be a good idea -- haven't tried it ... */ |
---|
1042 | if (bestlen > 0 && spsiz > bestlen) |
---|
1043 | spsiz = bestlen; |
---|
1044 | #endif /* COMMENT */ |
---|
1045 | if (spsiz < 20) spsiz = 20; |
---|
1046 | debug(F101,"input N cut packet length","",spsiz); |
---|
1047 | } |
---|
1048 | } |
---|
1049 | #endif /* NEWDPL */ |
---|
1050 | freerpkt(rsn); /* Free buffer where NAK lies. */ |
---|
1051 | if (y == 0) { /* In current window */ |
---|
1052 | debug(F100," in window","",0); |
---|
1053 | k = sseqtbl[rsn]; /* Get pointer to NAK'd packet. */ |
---|
1054 | if (k < 0 || (k > -1 && s_pkt[k].pk_typ == ' ')) { |
---|
1055 | x = resend(winlo); /* Packet we haven't sent yet. */ |
---|
1056 | } else { |
---|
1057 | x = resend(rsn); /* Resend requested packet. */ |
---|
1058 | } |
---|
1059 | if (x < 0) { /* Resend error is fatal. */ |
---|
1060 | type = 'E'; |
---|
1061 | errpkt((CHAR *)"Too many retries"); |
---|
1062 | break; |
---|
1063 | } else continue; /* Resend ok, go read another packet */ |
---|
1064 | } else if ((rsn == (pktnum + 1) % 64)) { /* NAK for next pkt */ |
---|
1065 | if (wslots > 1) { |
---|
1066 | debug( F101,"NAK for next packet, windowing","",rsn); |
---|
1067 | x = resend(winlo); /* Resend window-low */ |
---|
1068 | if (x < 0) { |
---|
1069 | type = 'E'; |
---|
1070 | errpkt((CHAR *)"Too many retries"); |
---|
1071 | break; |
---|
1072 | } |
---|
1073 | continue; /* Go back and read another pkt */ |
---|
1074 | } |
---|
1075 | debug(F101,"NAK for next packet, no windowing","",rsn); |
---|
1076 | x = (rsn == 0) ? 63 : rsn - 1; |
---|
1077 | if (x == 0 && (sndtyp == 'S' || sndtyp == 'I')) { |
---|
1078 | resend(0); /* ACK for S or I packet missing */ |
---|
1079 | continue; /* so resend the S or I */ |
---|
1080 | } |
---|
1081 | rsn = x; /* Else, treat NAK(n+1) as ACK(n) */ |
---|
1082 | nak2ack = 1; /* Go back and process the ACK */ |
---|
1083 | continue; |
---|
1084 | } else if (y > 0) { /* NAK for pkt we can't resend */ |
---|
1085 | debug(F101," NAK out of window","",rsn); /* bad... */ |
---|
1086 | type = 'E'; |
---|
1087 | errpkt((CHAR *)"NAK out of window"); |
---|
1088 | break; |
---|
1089 | } else continue; /* Ignore other NAKs */ |
---|
1090 | } /* End of file-sender NAK handler */ |
---|
1091 | |
---|
1092 | if (rsn == winlo) { /* Not ACK, NAK, timeout, etc. */ |
---|
1093 | debug(F000,"input send unexpected type","",type); |
---|
1094 | break; |
---|
1095 | } |
---|
1096 | } /* End of file-sender section */ |
---|
1097 | } /* End of input() while() loop */ |
---|
1098 | /* |
---|
1099 | When the window size is 1 and we have the packet we want, there can not |
---|
1100 | possibly be anything waiting for us on the connection that is useful to us. |
---|
1101 | However, there might be redundant copies of a packet we already got, which |
---|
1102 | would cause needless cycles of repeated packets. Therefore we flush the |
---|
1103 | communications input buffer now to try to get rid of undesired and unneeded |
---|
1104 | packets that we have not read yet. |
---|
1105 | */ |
---|
1106 | if (wslotn == 1 /* (not wslots!) */ |
---|
1107 | #ifdef STREAMING |
---|
1108 | && !streaming /* But not when streaming */ |
---|
1109 | #endif /* STREAMING */ |
---|
1110 | ) { |
---|
1111 | debug(F100,"input about to flush","",0); |
---|
1112 | ttflui(); /* Got what we want, clear input buffer. */ |
---|
1113 | } |
---|
1114 | #ifndef NEWDPL |
---|
1115 | if (!nakstate) /* When sending */ |
---|
1116 | rcalcpsz(); /* recalculate size every packet */ |
---|
1117 | #endif /* NEWDPL */ |
---|
1118 | if (type == 'E') |
---|
1119 | xitsta |= (what ? what : 1); /* Remember what failed. */ |
---|
1120 | debug(F101,"input winlo","",winlo); |
---|
1121 | debug(F101,"input rsn","",rsn); |
---|
1122 | debug(F000,"input returning type","",type); |
---|
1123 | return(rcvtyp = type); /* Success, return packet type. */ |
---|
1124 | } |
---|
1125 | |
---|
1126 | #ifdef PARSENSE |
---|
1127 | /* P A R C H K -- Check if Kermit packet has parity */ |
---|
1128 | |
---|
1129 | /* |
---|
1130 | Call with s = pointer to packet, start = packet start character, n = length. |
---|
1131 | Returns 0 if packet has no parity, -1 on error, or, if packet has parity: |
---|
1132 | 'e' for even, 'o' for odd, 'm' for mark. Space parity cannot be sensed. |
---|
1133 | So a return value of 0 really means either space or none. |
---|
1134 | Returns -2 if parity has already been checked during this protocol operation. |
---|
1135 | */ |
---|
1136 | int |
---|
1137 | #ifdef CK_ANSIC |
---|
1138 | parchk(CHAR *s, CHAR start, int n) |
---|
1139 | #else |
---|
1140 | parchk(s,start,n) CHAR *s, start; int n; |
---|
1141 | #endif /* CK_ANSIC */ |
---|
1142 | /* parchk */ { |
---|
1143 | CHAR s0, s1, s2, s3; |
---|
1144 | |
---|
1145 | debug(F101,"parchk n","",n); |
---|
1146 | debug(F101,"parchk start","",start); |
---|
1147 | |
---|
1148 | s0 = s[0] & 0x7f; /* Mark field (usually Ctrl-A) */ |
---|
1149 | |
---|
1150 | if (s0 != start || n < 5) return(-1); /* Not a valid packet */ |
---|
1151 | |
---|
1152 | /* Look at packet control fields, which never have 8th bit set */ |
---|
1153 | /* First check for no parity, most common case. */ |
---|
1154 | |
---|
1155 | if (((s[0] | s[1] | s[2] | s[3]) & 0x80) == 0) |
---|
1156 | return(0); /* No parity or space parity */ |
---|
1157 | |
---|
1158 | /* Check for mark parity */ |
---|
1159 | |
---|
1160 | if (((s[0] & s[1] & s[2] & s[3]) & 0x80) == 0x80) |
---|
1161 | return('m'); /* Mark parity */ |
---|
1162 | |
---|
1163 | /* Packet has some kind of parity */ |
---|
1164 | /* Make 7-bit copies of control fields */ |
---|
1165 | |
---|
1166 | s1 = s[1] & 0x7f; /* LEN */ |
---|
1167 | s2 = s[2] & 0x7f; /* SEQ */ |
---|
1168 | s3 = s[3] & 0x7f; /* TYPE */ |
---|
1169 | |
---|
1170 | /* Check for even parity */ |
---|
1171 | |
---|
1172 | if ((s[0] == p_tbl[s0]) && |
---|
1173 | (s[1] == p_tbl[s1]) && |
---|
1174 | (s[2] == p_tbl[s2]) && |
---|
1175 | (s[3] == p_tbl[s3])) |
---|
1176 | return('e'); |
---|
1177 | |
---|
1178 | /* Check for odd parity */ |
---|
1179 | |
---|
1180 | if ((s[0] != p_tbl[s0]) && |
---|
1181 | (s[1] != p_tbl[s1]) && |
---|
1182 | (s[2] != p_tbl[s2]) && |
---|
1183 | (s[3] != p_tbl[s3])) |
---|
1184 | return('o'); |
---|
1185 | |
---|
1186 | /* Otherwise it's probably line noise. Let checksum calculation catch it. */ |
---|
1187 | |
---|
1188 | return(-1); |
---|
1189 | } |
---|
1190 | #endif /* PARSENSE */ |
---|
1191 | |
---|
1192 | /* |
---|
1193 | Check to make sure timeout intervals are long enough to allow maximum |
---|
1194 | length packets to get through before the timer goes off. If not, the |
---|
1195 | timeout interval is adjusted upwards. |
---|
1196 | |
---|
1197 | This routine is called at the beginning of a transaction, before we |
---|
1198 | know anything about the delay characteristics of the line. It works |
---|
1199 | only for serial communication devices; it trusts the speed reported by |
---|
1200 | the operating system. |
---|
1201 | |
---|
1202 | Call with a timout interval. Returns it, adjusted if necessary. |
---|
1203 | */ |
---|
1204 | int |
---|
1205 | chktimo(timo,flag) int timo, flag; { |
---|
1206 | long cps, z; int x, y; |
---|
1207 | #ifdef STREAMING |
---|
1208 | debug(F101,"chktimo streaming","",streaming); |
---|
1209 | if (streaming) |
---|
1210 | return(0); |
---|
1211 | #endif /* STREAMING */ |
---|
1212 | |
---|
1213 | debug(F101,"chktimo timo","",timo); /* Timeout before adjustment */ |
---|
1214 | debug(F101,"chktimo flag","",flag); |
---|
1215 | |
---|
1216 | if (flag) /* Don't change timeout if user */ |
---|
1217 | return(timo); /* gave SET SEND TIMEOUT command. */ |
---|
1218 | debug(F101,"chktimo spmax","",spmax); |
---|
1219 | debug(F101,"chktimo urpsiz","",urpsiz); |
---|
1220 | |
---|
1221 | if (!network) { /* On serial connections... */ |
---|
1222 | speed = ttgspd(); /* Get current speed. */ |
---|
1223 | if (speed > 0L) { |
---|
1224 | cps = speed / 10L; /* Convert to chars per second */ |
---|
1225 | if (cps > 0L) { |
---|
1226 | long plen; /* Maximum of send and rcv pkt size */ |
---|
1227 | z = cps * (long) timo; /* Chars per timeout interval */ |
---|
1228 | z -= z / 10L; /* Less 10 percent */ |
---|
1229 | plen = spmax; |
---|
1230 | if (urpsiz > spmax) plen = urpsiz; |
---|
1231 | debug(F101,"chktimo plen","",plen); |
---|
1232 | if (z < plen) { /* Compare with packet size */ |
---|
1233 | x = (int) ((long) plen / cps); /* Adjust if necessary */ |
---|
1234 | y = x / 10; /* Add 10 percent for safety */ |
---|
1235 | if (y < 2) y = 2; /* Or 2 seconds, whichever is more */ |
---|
1236 | x += y; |
---|
1237 | if (x > timo) /* If this is greater than current */ |
---|
1238 | timo = x; /* timeout, change the timeout */ |
---|
1239 | debug(F101,"chktimo new timo","",timo); |
---|
1240 | } |
---|
1241 | } |
---|
1242 | } |
---|
1243 | } |
---|
1244 | return(timo); |
---|
1245 | } |
---|
1246 | |
---|
1247 | /* S P A C K -- Construct and send a packet */ |
---|
1248 | |
---|
1249 | /* |
---|
1250 | spack() sends a packet of the given type, sequence number n, with len data |
---|
1251 | characters pointed to by d, in either a regular or extended- length packet, |
---|
1252 | depending on len. Returns the number of bytes actually sent, or else -1 |
---|
1253 | upon failure. Uses global npad, padch, mystch, bctu, data. Leaves packet |
---|
1254 | fully built and null-terminated for later retransmission by resend(). |
---|
1255 | Updates global sndpktl (send-packet length). |
---|
1256 | |
---|
1257 | NOTE: The global pointer "data" is assumed to point into the 7th position |
---|
1258 | of a character array (presumably in packet buffer for the current packet). |
---|
1259 | It was used by getpkt() to build the packet data field. spack() fills in |
---|
1260 | the header to the left of the data pointer (the data pointer is defined |
---|
1261 | in getsbuf() in ckcfn3.c). If the address "d" is the same as "data", then |
---|
1262 | the packet's data field has been built "in place" and need not be copied. |
---|
1263 | */ |
---|
1264 | int |
---|
1265 | #ifdef CK_ANSIC |
---|
1266 | spack(char pkttyp, int n, int len, CHAR *d) |
---|
1267 | #else |
---|
1268 | spack(pkttyp,n,len,d) char pkttyp; int n, len; CHAR *d; |
---|
1269 | #endif /* CK_ANSIC */ |
---|
1270 | /* spack */ { |
---|
1271 | register int i; |
---|
1272 | int ix, j, k, x, lp, longpkt, copy, loglen; |
---|
1273 | |
---|
1274 | #ifdef GFTIMER |
---|
1275 | CKFLOAT t1 = 0.0, t2 = 0.0; |
---|
1276 | #endif /* GFTIMER */ |
---|
1277 | |
---|
1278 | register CHAR *cp, *mydata; |
---|
1279 | unsigned crc; |
---|
1280 | |
---|
1281 | copy = (d != data); /* Flag whether data must be copied */ |
---|
1282 | |
---|
1283 | #ifdef DEBUG |
---|
1284 | if (deblog) { /* Save lots of function calls! */ |
---|
1285 | debug(F101,"spack n","",n); |
---|
1286 | if (pkttyp != 'D') { /* Data packets would be too long */ |
---|
1287 | debug(F111,"spack data",data,data); |
---|
1288 | debug(F111,"spack d",d,d); |
---|
1289 | } |
---|
1290 | debug(F101,"spack len","",len); |
---|
1291 | debug(F101,"spack copy","",copy); |
---|
1292 | } |
---|
1293 | #endif /* DEBUG */ |
---|
1294 | |
---|
1295 | longpkt = (len + bctl + 2) > 94; /* Decide whether it's a long packet */ |
---|
1296 | mydata = data - 7 + (longpkt ? 0 : 3); /* Starting position of header */ |
---|
1297 | k = sseqtbl[n]; /* Packet structure info for pkt n */ |
---|
1298 | #ifdef DEBUG |
---|
1299 | if (deblog) { /* Save 2 more function calls... */ |
---|
1300 | debug(F101,"spack mydata","",mydata); |
---|
1301 | debug(F101,"spack sseqtbl[n]","",k); |
---|
1302 | if (k < 0) { |
---|
1303 | #ifdef STREAMING |
---|
1304 | if (!streaming) |
---|
1305 | #endif /* STREAMING */ |
---|
1306 | debug(F101,"spack sending packet out of window","",n); |
---|
1307 | } |
---|
1308 | } |
---|
1309 | #endif /* DEBUG */ |
---|
1310 | if (k > -1) { |
---|
1311 | s_pkt[k].pk_adr = mydata; /* Remember address of packet. */ |
---|
1312 | s_pkt[k].pk_seq = n; /* Record sequence number */ |
---|
1313 | s_pkt[k].pk_typ = pkttyp; /* Record packet type */ |
---|
1314 | } |
---|
1315 | spktl = 0; /* Initialize length of this packet */ |
---|
1316 | i = 0; /* and position in packet. */ |
---|
1317 | |
---|
1318 | /* Now fill the packet */ |
---|
1319 | |
---|
1320 | mydata[i++] = mystch; /* MARK */ |
---|
1321 | lp = i++; /* Position of LEN, fill in later */ |
---|
1322 | |
---|
1323 | mydata[i++] = tochar(n); /* SEQ field */ |
---|
1324 | mydata[i++] = pkttyp; /* TYPE field */ |
---|
1325 | j = len + bctl; /* Length of data + block check */ |
---|
1326 | if (longpkt) { /* Long packet? */ |
---|
1327 | int x; /* Yes, work around SCO Xenix/286 */ |
---|
1328 | #ifdef CKTUNING |
---|
1329 | unsigned int chk; |
---|
1330 | #endif /* CKTUNING */ |
---|
1331 | x = j / 95; /* compiler bug... */ |
---|
1332 | mydata[lp] = tochar(0); /* Set LEN to zero */ |
---|
1333 | mydata[i++] = tochar(x); /* Extended length, high byte */ |
---|
1334 | mydata[i++] = tochar(j % 95); /* Extended length, low byte */ |
---|
1335 | #ifdef CKTUNING |
---|
1336 | /* Header checksum - skip the function calls and loops */ |
---|
1337 | chk = (unsigned) mydata[lp] + |
---|
1338 | (unsigned) mydata[lp+1] + |
---|
1339 | (unsigned) mydata[lp+2] + |
---|
1340 | (unsigned) mydata[lp+3] + |
---|
1341 | (unsigned) mydata[lp+4] ; |
---|
1342 | mydata[i++] = tochar((CHAR) ((((chk & 0300) >> 6) + chk) & 077)); |
---|
1343 | #else |
---|
1344 | mydata[i] = '\0'; /* Terminate for header checksum */ |
---|
1345 | mydata[i++] = tochar(chk1(mydata+lp,5)); |
---|
1346 | #endif /* CKTUNING */ |
---|
1347 | } else mydata[lp] = tochar(j+2); /* Normal LEN */ |
---|
1348 | /* |
---|
1349 | When sending a file, the data is already in the right place. If it weren't, |
---|
1350 | it might make sense to optimize this section by using memcpy or bcopy |
---|
1351 | (neither of which are portable), but only if our packets were rather long. |
---|
1352 | When receiving, we're only sending ACKs so it doesn't matter. So count the |
---|
1353 | following loop as a sleeping dog. |
---|
1354 | */ |
---|
1355 | if (copy) /* Data field built in place? */ |
---|
1356 | for ( ; len--; i++) mydata[i] = *d++; /* No, must copy. */ |
---|
1357 | else /* Otherwise, */ |
---|
1358 | i += len; /* Just skip past data field. */ |
---|
1359 | mydata[i] = '\0'; /* Null-terminate for checksum calc. */ |
---|
1360 | |
---|
1361 | switch (bctu) { /* Block check */ |
---|
1362 | case 1: /* 1 = 6-bit chksum */ |
---|
1363 | ix = i - lp; /* Avoid "order of operation" error */ |
---|
1364 | mydata[i++] = tochar(chk1(mydata+lp,ix)); |
---|
1365 | break; |
---|
1366 | case 2: /* 2 = 12-bit chksum */ |
---|
1367 | j = chk2(mydata+lp,i-lp); |
---|
1368 | mydata[i++] = (unsigned)tochar((j >> 6) & 077); |
---|
1369 | mydata[i++] = (unsigned)tochar(j & 077); |
---|
1370 | break; |
---|
1371 | case 3: /* 3 = 16-bit CRC */ |
---|
1372 | crc = chk3(mydata+lp,i-lp); |
---|
1373 | mydata[i++] = (unsigned)tochar(((crc & 0170000)) >> 12); |
---|
1374 | mydata[i++] = (unsigned)tochar((crc >> 6) & 077); |
---|
1375 | mydata[i++] = (unsigned)tochar(crc & 077); |
---|
1376 | break; |
---|
1377 | case 4: /* 2 = 12-bit chksum, blank-free */ |
---|
1378 | j = chk2(mydata+lp,i-lp); |
---|
1379 | mydata[i++] = |
---|
1380 | (unsigned)(tochar((unsigned)(((j >> 6) & 077) + 1))); |
---|
1381 | mydata[i++] = (unsigned)(tochar((unsigned)((j & 077) + 1))); |
---|
1382 | break; |
---|
1383 | } |
---|
1384 | loglen = i; |
---|
1385 | mydata[i++] = seol; /* End of line (packet terminator) */ |
---|
1386 | #ifdef TCPSOCKET |
---|
1387 | /* |
---|
1388 | If TELNET connection and packet terminator is carriage return, |
---|
1389 | we must stuff either LF or NUL, according to SET TELNET NEWLINE-MODE |
---|
1390 | (tn_nlm), to meet the TELNET NVT specification, unless user said RAW. |
---|
1391 | |
---|
1392 | If NEWLINE-MODE is set to LF instead of CR, we still send CR-NUL |
---|
1393 | on a NVT connection and CR on a binary connection. |
---|
1394 | */ |
---|
1395 | if ( |
---|
1396 | #ifdef STREAMING |
---|
1397 | !dontsend && |
---|
1398 | #endif /* STREAMING */ |
---|
1399 | ((network && ttnproto == NP_TELNET) || (!local && sstelnet)) |
---|
1400 | && seol == CR) { |
---|
1401 | switch (TELOPT_ME(TELOPT_BINARY) ? tn_b_nlm : tn_nlm) { |
---|
1402 | case TNL_CR: /* NVT or BINARY */ |
---|
1403 | break; |
---|
1404 | case TNL_CRNUL: |
---|
1405 | mydata[i++] = NUL; |
---|
1406 | break; |
---|
1407 | case TNL_CRLF: |
---|
1408 | mydata[i++] = LF; |
---|
1409 | break; |
---|
1410 | } |
---|
1411 | } |
---|
1412 | #endif /* TCPSOCKET */ |
---|
1413 | mydata[i] = '\0'; /* Terminate string */ |
---|
1414 | if ( |
---|
1415 | #ifdef STREAMING |
---|
1416 | !dontsend && |
---|
1417 | #endif /* STREAMING */ |
---|
1418 | pktlog |
---|
1419 | ) /* Save a function call! */ |
---|
1420 | logpkt('s',n,mydata,loglen); /* Log the packet */ |
---|
1421 | |
---|
1422 | /* (PWP) add the parity quickly at the end */ |
---|
1423 | if (parity) { |
---|
1424 | switch (parity) { |
---|
1425 | case 'e': /* Even */ |
---|
1426 | for (cp = &mydata[i-1]; cp >= mydata; cp--) |
---|
1427 | *cp = p_tbl[*cp]; |
---|
1428 | break; |
---|
1429 | case 'm': /* Mark */ |
---|
1430 | for (cp = &mydata[i-1]; cp >= mydata; cp--) |
---|
1431 | *cp |= 128; |
---|
1432 | break; |
---|
1433 | case 'o': /* Odd */ |
---|
1434 | for (cp = &mydata[i-1]; cp >= mydata; cp--) |
---|
1435 | *cp = p_tbl[*cp] ^ 128; |
---|
1436 | break; |
---|
1437 | case 's': /* Space */ |
---|
1438 | for (cp = &mydata[i-1]; cp >= mydata; cp--) |
---|
1439 | *cp &= 127; |
---|
1440 | break; |
---|
1441 | } |
---|
1442 | } |
---|
1443 | if (pktpaus) msleep(pktpaus); /* Pause if requested */ |
---|
1444 | x = 0; |
---|
1445 | |
---|
1446 | if (npad) { |
---|
1447 | #ifdef STREAMING |
---|
1448 | if (dontsend) |
---|
1449 | x = 0; |
---|
1450 | else |
---|
1451 | #endif /* STREAMING */ |
---|
1452 | x = ttol(padbuf,npad); /* Send any padding */ |
---|
1453 | } |
---|
1454 | if (x > -1) { |
---|
1455 | #ifdef CK_TIMERS |
---|
1456 | if (timint > 0) { |
---|
1457 | if (pkttyp == 'N') |
---|
1458 | srttbl[n > 0 ? n-1 : 63] = gtimer(); |
---|
1459 | else |
---|
1460 | srttbl[n] = gtimer(); |
---|
1461 | } |
---|
1462 | #endif /* CK_TIMERS */ |
---|
1463 | spktl = i; /* Remember packet length */ |
---|
1464 | if (k > -1) |
---|
1465 | s_pkt[k].pk_len = spktl; /* also in packet info structure */ |
---|
1466 | |
---|
1467 | #ifdef DEBUG |
---|
1468 | #ifdef GFTIMER |
---|
1469 | /* |
---|
1470 | This code shows (in the debug log) how long it takes write() to execute. |
---|
1471 | Sometimes on a congested TCP connection, it can surprise you -- 90 seconds |
---|
1472 | or more... |
---|
1473 | */ |
---|
1474 | if ( |
---|
1475 | #ifdef STREAMING |
---|
1476 | !dontsend && |
---|
1477 | #endif /* STREAMING */ |
---|
1478 | deblog |
---|
1479 | ) |
---|
1480 | t1 = gftimer(); |
---|
1481 | #endif /* GFTIMER */ |
---|
1482 | #endif /* DEBUG */ |
---|
1483 | |
---|
1484 | #ifdef STREAMING |
---|
1485 | if (dontsend) { |
---|
1486 | debug(F000,"STREAMING spack skipping","",pkttyp); |
---|
1487 | x = 0; |
---|
1488 | } else |
---|
1489 | #endif /* STREAMING */ |
---|
1490 | x = ttol(mydata,spktl); /* Send the packet */ |
---|
1491 | } |
---|
1492 | #ifdef STREAMING |
---|
1493 | if (!dontsend) { |
---|
1494 | #endif /* STREAMING */ |
---|
1495 | debug(F101,"spack spktl","",spktl); |
---|
1496 | debug(F101,"spack ttol returns","",x); |
---|
1497 | if (x < 0) { /* Failed. */ |
---|
1498 | if (local && x < -1) { |
---|
1499 | xxscreen(SCR_ST,ST_ERR,0L,"FAILED: Connection lost"); |
---|
1500 | /* We can't send an E packet because the connection is lost. */ |
---|
1501 | epktsent = 1; /* So pretend we sent one. */ |
---|
1502 | fatalio = 1; /* Remember we got a fatal i/o error */ |
---|
1503 | dologend(); |
---|
1504 | ckstrncpy((char *)epktmsg,"Connection lost",PKTMSGLEN); |
---|
1505 | } |
---|
1506 | return(x); |
---|
1507 | } |
---|
1508 | if (spktl > maxsend) /* Keep track of longest packet sent */ |
---|
1509 | maxsend = spktl; |
---|
1510 | #ifdef DEBUG |
---|
1511 | #ifdef GFTIMER |
---|
1512 | if (deblog) { /* Log elapsed time for write() */ |
---|
1513 | t2 = gftimer(); |
---|
1514 | debug(F101,"spack ttol msec","",(long)((t2-t1)*1000.0)); |
---|
1515 | } |
---|
1516 | #endif /* GFTIMER */ |
---|
1517 | #endif /* DEBUG */ |
---|
1518 | #ifdef STREAMING |
---|
1519 | } |
---|
1520 | #endif /* STREAMING */ |
---|
1521 | |
---|
1522 | sndtyp = pkttyp; /* Remember packet type for echos */ |
---|
1523 | #ifdef STREAMING |
---|
1524 | if (!dontsend) { /* If really sent, */ |
---|
1525 | spackets++; /* count it. */ |
---|
1526 | flco += spktl; /* Count the characters */ |
---|
1527 | tlco += spktl; /* for statistics... */ |
---|
1528 | #ifdef DEBUG |
---|
1529 | if (deblog) { /* Save two function calls! */ |
---|
1530 | dumpsbuf(); /* Dump send buffers to debug log */ |
---|
1531 | debug(F111,"spack calling screen, mydata=",mydata,n); |
---|
1532 | } |
---|
1533 | #endif /* DEBUG */ |
---|
1534 | } |
---|
1535 | #endif /* STREAMING */ |
---|
1536 | if (local) { |
---|
1537 | int x = 0; |
---|
1538 | if (fdispla != XYFD_N) x = 1; |
---|
1539 | if ((fdispla == XYFD_B) && (pkttyp == 'D' || pkttyp == 'Y')) x = 0; |
---|
1540 | if (x) |
---|
1541 | xxscreen(SCR_PT,pkttyp,(long)n,(char *)mydata); /* Update screen */ |
---|
1542 | } |
---|
1543 | return(spktl); /* Return length */ |
---|
1544 | } |
---|
1545 | |
---|
1546 | /* C H K 1 -- Compute a type-1 Kermit 6-bit checksum. */ |
---|
1547 | |
---|
1548 | int |
---|
1549 | chk1(pkt,len) register CHAR *pkt; register int len; { |
---|
1550 | register unsigned int chk; |
---|
1551 | #ifdef CKTUNING |
---|
1552 | #ifdef COMMENT |
---|
1553 | register unsigned int m; /* Avoid function call */ |
---|
1554 | m = (parity) ? 0177 : 0377; |
---|
1555 | for (chk = 0; len-- > 0; pkt++) |
---|
1556 | chk += *pkt & m; |
---|
1557 | #else |
---|
1558 | chk = 0; |
---|
1559 | while (len-- > 0) chk += (unsigned) *pkt++; |
---|
1560 | #endif /* COMMENT */ |
---|
1561 | #else |
---|
1562 | chk = chk2(pkt,len); |
---|
1563 | #endif /* CKTUNING */ |
---|
1564 | chk = (((chk & 0300) >> 6) + chk) & 077; |
---|
1565 | debug(F101,"chk1","",chk); |
---|
1566 | return((int) chk); |
---|
1567 | } |
---|
1568 | |
---|
1569 | /* C H K 2 -- Compute the numeric sum of all the bytes in the packet. */ |
---|
1570 | |
---|
1571 | unsigned int |
---|
1572 | chk2(pkt,len) register CHAR *pkt; register int len; { |
---|
1573 | register long chk; |
---|
1574 | #ifdef COMMENT |
---|
1575 | register unsigned int m; |
---|
1576 | m = (parity) ? 0177 : 0377; |
---|
1577 | for (chk = 0; len-- > 0; pkt++) |
---|
1578 | chk += *pkt & m; |
---|
1579 | #else |
---|
1580 | /* Parity has already been stripped */ |
---|
1581 | chk = 0L; |
---|
1582 | while (len-- > 0) chk += (unsigned) *pkt++; |
---|
1583 | #endif /* COMMENT */ |
---|
1584 | debug(F101,"chk2","",(unsigned int) (chk & 07777)); |
---|
1585 | return((unsigned int) (chk & 07777)); |
---|
1586 | } |
---|
1587 | |
---|
1588 | /* C H K 3 -- Compute a type-3 Kermit block check. */ |
---|
1589 | /* |
---|
1590 | Calculate the 16-bit CRC-CCITT of a null-terminated string using a lookup |
---|
1591 | table. Assumes the argument string contains no embedded nulls. |
---|
1592 | */ |
---|
1593 | #ifdef COMMENT |
---|
1594 | unsigned int |
---|
1595 | chk3(pkt,parity,len) register CHAR *pkt; int parity; register int len; { |
---|
1596 | register long c, crc; |
---|
1597 | register unsigned int m; |
---|
1598 | m = (parity) ? 0177 : 0377; |
---|
1599 | for (crc = 0; len-- > 0; pkt++) { |
---|
1600 | c = crc ^ (long)(*pkt & m); |
---|
1601 | crc = (crc >> 8) ^ (crcta[(c & 0xF0) >> 4] ^ crctb[c & 0x0F]); |
---|
1602 | } |
---|
1603 | return((unsigned int) (crc & 0xFFFF)); |
---|
1604 | } |
---|
1605 | #else |
---|
1606 | unsigned int |
---|
1607 | chk3(pkt,len) register CHAR *pkt; register int len; { |
---|
1608 | register long c, crc; |
---|
1609 | for (crc = 0; len-- > 0; pkt++) { |
---|
1610 | c = crc ^ (long)(*pkt); |
---|
1611 | crc = (crc >> 8) ^ (crcta[(c & 0xF0) >> 4] ^ crctb[c & 0x0F]); |
---|
1612 | } |
---|
1613 | debug(F101,"chk3","",(unsigned int) (crc & 0xFFFF)); |
---|
1614 | return((unsigned int) (crc & 0xFFFF)); |
---|
1615 | } |
---|
1616 | #endif /* COMMENT */ |
---|
1617 | |
---|
1618 | /* N X T P K T -- Next Packet */ |
---|
1619 | /* |
---|
1620 | Get packet number of next packet to send and allocate a buffer for it. |
---|
1621 | Returns: |
---|
1622 | 0 on success, with global pktnum set to the packet number; |
---|
1623 | -1 on failure to allocate buffer (fatal); |
---|
1624 | -2 if resulting packet number is outside the current window. |
---|
1625 | */ |
---|
1626 | int |
---|
1627 | nxtpkt() { /* Called by file sender */ |
---|
1628 | int j, n, x; |
---|
1629 | |
---|
1630 | debug(F101,"nxtpkt pktnum","",pktnum); |
---|
1631 | debug(F101,"nxtpkt winlo ","",winlo); |
---|
1632 | n = (pktnum + 1) % 64; /* Increment packet number mod 64 */ |
---|
1633 | debug(F101,"nxtpkt n","",n); |
---|
1634 | #ifdef STREAMING |
---|
1635 | if (!streaming) { |
---|
1636 | x = chkwin(n,winlo,wslots); /* Don't exceed window boundary */ |
---|
1637 | debug(F101,"nxtpkt chkwin","",x); |
---|
1638 | if (x) |
---|
1639 | return(-2); |
---|
1640 | j = getsbuf(n); /* Get a buffer for packet n */ |
---|
1641 | if (j < 0) { |
---|
1642 | debug(F101,"nxtpkt getsbuf failure","",j); |
---|
1643 | return(-1); |
---|
1644 | } |
---|
1645 | } |
---|
1646 | #endif /* STREAMING */ |
---|
1647 | pktnum = n; |
---|
1648 | return(0); |
---|
1649 | } |
---|
1650 | |
---|
1651 | /* Functions for sending ACKs and NAKs */ |
---|
1652 | |
---|
1653 | /* Note, we should only ACK the packet at window-low (winlo) */ |
---|
1654 | /* However, if an old packet arrives again (e.g. because the ACK we sent */ |
---|
1655 | /* earlier was lost), we ACK it again. */ |
---|
1656 | |
---|
1657 | int |
---|
1658 | ack() { /* Acknowledge the current packet. */ |
---|
1659 | return(ackns(winlo,(CHAR *)"")); |
---|
1660 | } |
---|
1661 | |
---|
1662 | #ifdef STREAMING |
---|
1663 | int |
---|
1664 | fastack() { /* Acknowledge packet n */ |
---|
1665 | int j, k, n, x; |
---|
1666 | n = winlo; |
---|
1667 | |
---|
1668 | k = rseqtbl[n]; /* First find received packet n. */ |
---|
1669 | debug(F101,"STREAMING fastack k","",k); |
---|
1670 | freesbuf(n); /* Free current send-buffer, if any */ |
---|
1671 | if ((j = getsbuf(n)) < 0) { |
---|
1672 | /* This can happen if we have to re-ACK an old packet that has */ |
---|
1673 | /* already left the window. It does no harm. */ |
---|
1674 | debug(F101,"STREAMING fastack can't getsbuf","",n); |
---|
1675 | } |
---|
1676 | dontsend = 1; |
---|
1677 | x = spack('Y',n,0,(CHAR *)""); /* Now send it (but not really) */ |
---|
1678 | dontsend = 0; |
---|
1679 | if (x < 0) return(x); |
---|
1680 | debug(F101,"STREAMING fastack x","",x); |
---|
1681 | if (k > -1) |
---|
1682 | freerbuf(k); /* don't need it any more */ |
---|
1683 | if (j > -1) |
---|
1684 | freesbuf(j); /* and don't need to keep ACK either */ |
---|
1685 | winlo = (winlo + 1) % 64; |
---|
1686 | return(0); |
---|
1687 | } |
---|
1688 | #endif /* STREAMING */ |
---|
1689 | |
---|
1690 | int |
---|
1691 | ackns(n,s) int n; CHAR *s; { /* Acknowledge packet n */ |
---|
1692 | int j, k, x; |
---|
1693 | debug(F111,"ackns",s,n); |
---|
1694 | |
---|
1695 | k = rseqtbl[n]; /* First find received packet n. */ |
---|
1696 | debug(F101,"ackns k","",k); |
---|
1697 | freesbuf(n); /* Free current send-buffer, if any */ |
---|
1698 | if ((j = getsbuf(n)) < 0) { |
---|
1699 | /* This can happen if we have to re-ACK an old packet that has */ |
---|
1700 | /* already left the window. It does no harm. */ |
---|
1701 | debug(F101,"ackns can't getsbuf","",n); |
---|
1702 | } |
---|
1703 | x = spack('Y',n,(int)strlen((char *)s),s); /* Now send it. */ |
---|
1704 | if (x < 0) return(x); |
---|
1705 | debug(F101,"ackns winlo","",winlo); |
---|
1706 | debug(F101,"ackns n","",n); |
---|
1707 | if (n == winlo) { /* If we're acking winlo */ |
---|
1708 | if (k > -1) |
---|
1709 | freerbuf(k); /* don't need it any more */ |
---|
1710 | if (j > -1) |
---|
1711 | freesbuf(j); /* and don't need to keep ACK either */ |
---|
1712 | winlo = (winlo + 1) % 64; |
---|
1713 | } |
---|
1714 | return(0); |
---|
1715 | } |
---|
1716 | |
---|
1717 | int |
---|
1718 | ackn(n) int n; { /* Send ACK for packet number n */ |
---|
1719 | return(ackns(n,(CHAR *)"")); |
---|
1720 | } |
---|
1721 | |
---|
1722 | int |
---|
1723 | ack1(s) CHAR *s; { /* Send an ACK with data. */ |
---|
1724 | if (!s) s = (CHAR *)""; |
---|
1725 | debug(F110,"ack1",(char *)s,0); |
---|
1726 | return(ackns(winlo,s)); |
---|
1727 | } |
---|
1728 | |
---|
1729 | /* N A C K -- Send a Negative ACKnowledgment. */ |
---|
1730 | /* |
---|
1731 | Call with the packet number, n, to be NAK'd. |
---|
1732 | Returns -1 if that packet has been NAK'd too many times, otherwise 0. |
---|
1733 | Btw, it is not right to return 0 under error conditions. This is |
---|
1734 | done because the -1 code is used for cancelling the file transfer. |
---|
1735 | More work is needed here. |
---|
1736 | */ |
---|
1737 | int |
---|
1738 | nack(n) int n; { |
---|
1739 | int i, x; |
---|
1740 | |
---|
1741 | if (n < 0 || n > 63) { |
---|
1742 | debug(F101,"nack bad pkt num","",n); |
---|
1743 | return(0); |
---|
1744 | } else debug(F101,"nack","",n); |
---|
1745 | if ((i = sseqtbl[n]) < 0) { /* If necessary */ |
---|
1746 | if (getsbuf(n) < 0) { /* get a buffer for this NAK */ |
---|
1747 | debug(F101,"nack can't getsbuf","",n); |
---|
1748 | return(0); |
---|
1749 | } else i = sseqtbl[n]; /* New slot number */ |
---|
1750 | } |
---|
1751 | if (maxtry > 0 && s_pkt[i].pk_rtr++ > maxtry) /* How many? */ |
---|
1752 | return(-1); /* Too many... */ |
---|
1753 | |
---|
1754 | /* Note, don't free this buffer. Eventually an ACK will come, and that */ |
---|
1755 | /* will set it free. If not, well, it's back to ground zero anyway... */ |
---|
1756 | |
---|
1757 | x = spack('N',n,0,(CHAR *) ""); /* NAKs never have data. */ |
---|
1758 | return(x); |
---|
1759 | } |
---|
1760 | |
---|
1761 | #ifndef NEWDPL /* This routine no longer used */ |
---|
1762 | /* |
---|
1763 | * (PWP) recalculate the optimal packet length in the face of errors. |
---|
1764 | * This is a modified version of the algorithm by John Chandler in Kermit/370, |
---|
1765 | * see "Dynamic Packet Size Control", Kermit News, V2 #1, June 1988. |
---|
1766 | * |
---|
1767 | * This implementation minimizes the total overhead equation, which is |
---|
1768 | * |
---|
1769 | * Total chars = file_chars + (header_len * num_packs) |
---|
1770 | * + (errors * (header_len + packet_len)) |
---|
1771 | * |
---|
1772 | * Differentiate with respect to number of chars, solve for packet_len, get: |
---|
1773 | * |
---|
1774 | * packet_len = sqrt (file_chars * header_len / errors) |
---|
1775 | */ |
---|
1776 | |
---|
1777 | /* |
---|
1778 | (FDC) New super-simple algorithm. If there was an error in the most recent |
---|
1779 | packet exchange, cut the send-packet size in half, down to a minimum of 20. |
---|
1780 | If there was no error, increase the size by 5/4, up to the maximum negotiated |
---|
1781 | length. Seems to be much more responsive than previous algorithm, which took |
---|
1782 | forever to recover the original packet length, and it also went crazy under |
---|
1783 | certain conditions. |
---|
1784 | |
---|
1785 | Here's another idea for packet length resizing that keeps a history of the |
---|
1786 | last n packets. Push a 1 into the left end of an n-bit shift register if the |
---|
1787 | current packet is good, otherwise push a zero. The current n-bit value, w, of |
---|
1788 | this register is a weighted sum of the noise hits for the last n packets, with |
---|
1789 | the most recent weighing the most. The current packet length is some function |
---|
1790 | of w and the negotiated packet length, like: |
---|
1791 | |
---|
1792 | (2^n - w) / (2^n) * (negotiated length) |
---|
1793 | |
---|
1794 | If the present resizing method causes problems, think about this one a little |
---|
1795 | more. |
---|
1796 | */ |
---|
1797 | VOID |
---|
1798 | rcalcpsz() { |
---|
1799 | |
---|
1800 | #ifdef COMMENT |
---|
1801 | /* Old way */ |
---|
1802 | register long x, q; |
---|
1803 | if (numerrs == 0) return; /* bounds check just in case */ |
---|
1804 | |
---|
1805 | /* overhead on a data packet is npad+5+bctr, plus 3 if extended packet */ |
---|
1806 | /* an ACK is 5+bctr */ |
---|
1807 | |
---|
1808 | /* first set x = per packet overhead */ |
---|
1809 | if (wslots > 1) /* Sliding windows */ |
---|
1810 | x = (long) (npad+5+bctr); /* packet only, don't count ack */ |
---|
1811 | else /* Stop-n-wait */ |
---|
1812 | x = (long) (npad+5+3+bctr+5+bctr); /* count packet and ack. */ |
---|
1813 | |
---|
1814 | /* then set x = packet length ** 2 */ |
---|
1815 | x = x * ( ffc / (long) numerrs); /* careful of overflow */ |
---|
1816 | |
---|
1817 | /* calculate the long integer sqrt(x) quickly */ |
---|
1818 | q = 500; |
---|
1819 | q = (q + x/q) >> 1; |
---|
1820 | q = (q + x/q) >> 1; |
---|
1821 | q = (q + x/q) >> 1; |
---|
1822 | q = (q + x/q) >> 1; /* should converge in about 4 steps */ |
---|
1823 | if ((q > 94) && (q < 130)) /* break-even point for long packets */ |
---|
1824 | q = 94; |
---|
1825 | if (q > spmax) q = spmax; /* maximum bounds */ |
---|
1826 | if (q < 10) q = 10; /* minimum bounds */ |
---|
1827 | spsiz = q; /* set new send packet size */ |
---|
1828 | debug(F101,"rcalcpsiz","",q); |
---|
1829 | #else |
---|
1830 | /* New way */ |
---|
1831 | debug(F101,"rcalcpsiz numerrs","",numerrs); |
---|
1832 | debug(F101,"rcalcpsiz spsiz","",spsiz); |
---|
1833 | if (spackets < 3) { |
---|
1834 | numerrs = 0; |
---|
1835 | return; |
---|
1836 | } |
---|
1837 | if (numerrs) |
---|
1838 | spsiz = spsiz / 2; |
---|
1839 | else |
---|
1840 | spsiz = (spsiz / 4) * 5; |
---|
1841 | if (spsiz < 20) spsiz = 20; |
---|
1842 | if (spsiz > spmax) spsiz = spmax; |
---|
1843 | debug(F101,"rcalcpsiz new spsiz","",spsiz); |
---|
1844 | numerrs = 0; |
---|
1845 | #endif /* COMMENT */ |
---|
1846 | } |
---|
1847 | #endif /* NEWDPL */ |
---|
1848 | |
---|
1849 | /* R E S E N D -- Retransmit packet n. */ |
---|
1850 | |
---|
1851 | /* |
---|
1852 | Returns 0 or positive on success (the number of retries for packet n). |
---|
1853 | On failure, returns a negative number, and an error message is placed |
---|
1854 | in recpkt. |
---|
1855 | */ |
---|
1856 | int |
---|
1857 | resend(n) int n; { /* Send packet n again. */ |
---|
1858 | int j, k, x; |
---|
1859 | #ifdef GFTIMER |
---|
1860 | CKFLOAT t1 = 0.0, t2 = 0.0; |
---|
1861 | #endif /* GFTIMER */ |
---|
1862 | |
---|
1863 | debug(F101,"resend seq","",n); |
---|
1864 | |
---|
1865 | k = chkwin(n,winlo,wslots); /* See if packet in current window */ |
---|
1866 | j = -1; /* Assume it's lost */ |
---|
1867 | if (k == 0) j = sseqtbl[n]; /* See if we still have a copy of it */ |
---|
1868 | if (k != 0 || j < 0) { /* If not.... */ |
---|
1869 | if (nakstate && k == 1) { |
---|
1870 | /* |
---|
1871 | Packet n is in the previous window and we are the file receiver. |
---|
1872 | We already sent the ACK and deallocated its buffer so we can't just |
---|
1873 | retransmit the ACK. Rather than give up, we try some tricks... |
---|
1874 | */ |
---|
1875 | if (n == 0 && spackets < 63 && myinit[0]) { /* ACK to Send-Init */ |
---|
1876 | /* |
---|
1877 | If the packet number is 0, and we're at the beginning of a protocol |
---|
1878 | operation (spackets < 63), then we have to resend the ACK to an I or S |
---|
1879 | packet, complete with parameters in the data field. So we take a chance and |
---|
1880 | send a copy of the parameters in an ACK packet with block check type 1. |
---|
1881 | */ |
---|
1882 | int bctlsav; /* Temporary storage */ |
---|
1883 | int bctusav; |
---|
1884 | bctlsav = bctl; /* Save current block check length */ |
---|
1885 | bctusav = bctu; /* and type */ |
---|
1886 | bctu = bctl = 1; /* Set block check to 1 */ |
---|
1887 | x = spack('Y',0,(int)strlen((char *)myinit),(CHAR *)myinit); |
---|
1888 | if (x < 0) return(x); |
---|
1889 | logpkt('#',n,(CHAR *)"<reconstructed>",0); /* Log it */ |
---|
1890 | bctu = bctusav; /* Restore block check type */ |
---|
1891 | bctl = bctlsav; /* and length */ |
---|
1892 | |
---|
1893 | } else { /* Not the first packet */ |
---|
1894 | /* |
---|
1895 | It's not the first packet of the protocol operation. It's some other packet |
---|
1896 | that we have already ACK'd and forgotten about. So we take a chance and |
---|
1897 | send an empty ACK using the current block-check type. Usually this will |
---|
1898 | work out OK (like when acking Data packets), and no great harm will be done |
---|
1899 | if it was some other kind of packet (F, etc). If we are requesting an |
---|
1900 | interruption of the file transfer, the flags are still set, so we'll catch |
---|
1901 | up on the next packet. |
---|
1902 | */ |
---|
1903 | x = spack('Y',n,0,(CHAR *) ""); |
---|
1904 | if (x < 0) return(x); |
---|
1905 | } |
---|
1906 | retrans++; |
---|
1907 | xxscreen(SCR_PT,'%',(long)pktnum,"Retransmission"); |
---|
1908 | return(0); |
---|
1909 | } else { |
---|
1910 | /* |
---|
1911 | Packet number is not in current or previous window. We seem to hit this |
---|
1912 | code occasionally at the beginning of a transaction, for apparently no good |
---|
1913 | reason. Let's just log it for debugging, send nothing, and try to proceed |
---|
1914 | with the protocol rather than killing it. |
---|
1915 | */ |
---|
1916 | debug(F101,"resend PKT NOT IN WINDOW","",n); |
---|
1917 | debug(F101,"resend k","",k); |
---|
1918 | return(0); |
---|
1919 | } |
---|
1920 | } |
---|
1921 | |
---|
1922 | /* OK, it's in the window and it's not lost. */ |
---|
1923 | |
---|
1924 | debug(F101,"resend pktinfo index","",k); |
---|
1925 | |
---|
1926 | if (maxtry > 0 && s_pkt[j].pk_rtr++ > maxtry) { /* Over retry limit */ |
---|
1927 | xitsta |= what; |
---|
1928 | return(-1); |
---|
1929 | } |
---|
1930 | debug(F101,"resend retry","",s_pkt[j].pk_rtr); /* OK so far */ |
---|
1931 | dumpsbuf(); /* (debugging) */ |
---|
1932 | if (s_pkt[j].pk_typ == ' ') { /* Incompletely formed packet */ |
---|
1933 | if (nakstate) { /* (This shouldn't happen any more) */ |
---|
1934 | nack(n); |
---|
1935 | retrans++; |
---|
1936 | xxscreen(SCR_PT,'%',(long)pktnum,"(resend)"); |
---|
1937 | return(s_pkt[j].pk_rtr); |
---|
1938 | } else { /* No packet to resend! */ |
---|
1939 | #ifdef COMMENT |
---|
1940 | /* |
---|
1941 | This happened (once) while sending a file with 2 window slots and typing |
---|
1942 | X to the sender to cancel the file. But since we're cancelling anyway, |
---|
1943 | there's no need to give a scary message. |
---|
1944 | */ |
---|
1945 | sprintf((char *)epktmsg, |
---|
1946 | "resend logic error: NPS, n=%d, j=%d.",n,j); |
---|
1947 | return(-2); |
---|
1948 | #else |
---|
1949 | /* Just ignore it. */ |
---|
1950 | return(0); |
---|
1951 | #endif /* COMMENT */ |
---|
1952 | } |
---|
1953 | } |
---|
1954 | #ifdef DEBUG |
---|
1955 | #ifdef GFTIMER |
---|
1956 | if (deblog) t1 = gftimer(); |
---|
1957 | #endif /* GFTIMER */ |
---|
1958 | #endif /* DEBUG */ |
---|
1959 | |
---|
1960 | /* Everything ok, send the packet */ |
---|
1961 | #ifdef CK_TIMERS |
---|
1962 | if (timint > 0) |
---|
1963 | srttbl[n] = gtimer(); /* Update the timer */ |
---|
1964 | #endif /* CK_TIMERS */ |
---|
1965 | x = ttol(s_pkt[j].pk_adr,s_pkt[j].pk_len); |
---|
1966 | |
---|
1967 | #ifdef DEBUG |
---|
1968 | #ifdef GFTIMER |
---|
1969 | if (deblog) { |
---|
1970 | t2 = gftimer(); |
---|
1971 | debug(F101,"resend ttol msec","",(long)((t2-t1)*1000.0)); |
---|
1972 | } |
---|
1973 | #endif /* GFTIMER */ |
---|
1974 | #endif /* DEBUG */ |
---|
1975 | debug(F101,"resend ttol returns","",x); |
---|
1976 | |
---|
1977 | retrans++; /* Count a retransmission */ |
---|
1978 | xxscreen(SCR_PT,'%',(long)pktnum,"(resend)"); /* Tell user about resend */ |
---|
1979 | logpkt('S',n,s_pkt[j].pk_adr, s_pkt[j].pk_len); /* Log the resent packet */ |
---|
1980 | return(s_pkt[j].pk_rtr); /* Return the number of retries. */ |
---|
1981 | } |
---|
1982 | |
---|
1983 | /* E R R P K T -- Send an Error Packet */ |
---|
1984 | |
---|
1985 | int |
---|
1986 | errpkt(reason) CHAR *reason; { /* ...containing the reason given */ |
---|
1987 | extern int rtimo, state, justone; |
---|
1988 | int x, y; |
---|
1989 | czseen = 1; /* Also cancels batch */ |
---|
1990 | state = 0; /* Reset protocol state */ |
---|
1991 | debug(F110,"errpkt",reason,0); |
---|
1992 | tlog(F110,"Protocol Error:",(char *)reason,0L); |
---|
1993 | xxscreen(SCR_EM,0,0L,reason); |
---|
1994 | encstr(reason); |
---|
1995 | x = spack('E',pktnum,size,data); |
---|
1996 | ckstrncpy((char *)epktmsg,(char *)reason,PKTMSGLEN); |
---|
1997 | y = quiet; quiet = 1; epktsent = 1; /* Close files silently. */ |
---|
1998 | clsif(); clsof(1); |
---|
1999 | quiet = y; |
---|
2000 | /* |
---|
2001 | I just sent an E-packet. I'm in local mode, I was receiving a file, |
---|
2002 | I'm not a server, and sliding windows are in use. Therefore, there are |
---|
2003 | likely to be a bunch of packets already "in the pipe" on their way to me |
---|
2004 | by the time the remote sender gets the E-packet. So the next time I |
---|
2005 | CONNECT or try to start another protocol operation, I am likely to become |
---|
2006 | terribly confused by torrents of incoming material. To prevent this, |
---|
2007 | the following code soaks up packets from the connection until there is an |
---|
2008 | error or timeout, without wasting too much time waiting. |
---|
2009 | |
---|
2010 | Exactly the same problem occurs when I am in remote mode or if I am |
---|
2011 | in server mode with the justone flag set. In remote mode not only |
---|
2012 | does the packet data potentially get echo'd back to the sender which |
---|
2013 | is confusing to the user in CONNECT mode, but it also may result in the |
---|
2014 | host performing bizarre actions such as suspending the process if ^Z is |
---|
2015 | unprefixed, etc. |
---|
2016 | |
---|
2017 | Furthermore, thousands of packets bytes in the data stream prevent the |
---|
2018 | client from being able to process Telnet Kermit Option negotiations |
---|
2019 | properly. |
---|
2020 | */ |
---|
2021 | #ifdef STREAMING |
---|
2022 | /* Because streaming sets the timeout to 0... */ |
---|
2023 | if (streaming) { |
---|
2024 | timint = rcvtimo = rtimo; |
---|
2025 | streaming = 0; |
---|
2026 | } |
---|
2027 | #endif /* STREAMING */ |
---|
2028 | if (what & W_RECV && |
---|
2029 | (!server || (server && justone)) && |
---|
2030 | (wslots > 1 |
---|
2031 | #ifdef STREAMING |
---|
2032 | || streaming |
---|
2033 | #endif /* STREAMING */ |
---|
2034 | )) { |
---|
2035 | #ifdef GFTIMER |
---|
2036 | CKFLOAT oldsec, sec = (CKFLOAT) 0.0; |
---|
2037 | #else |
---|
2038 | int oldsec, sec = 0; |
---|
2039 | #endif /* GFTIMER */ |
---|
2040 | debug(F101,"errpkt draining","",wslots); |
---|
2041 | xxscreen(SCR_ST,ST_MSG,0l,"Draining incoming packets, wait..."); |
---|
2042 | while (x > -1) { /* Don't bother if no connection */ |
---|
2043 | oldsec = sec; |
---|
2044 | #ifdef GFTIMER |
---|
2045 | sec = gftimer(); |
---|
2046 | if (oldsec != (CKFLOAT) 0.0) |
---|
2047 | timint = rcvtimo = (int) (sec - oldsec + 0.5); |
---|
2048 | #else |
---|
2049 | sec = gtimer(); |
---|
2050 | if (oldsec != 0) |
---|
2051 | timint = rcvtimo = sec - oldsec + 1; |
---|
2052 | #endif /* GFTIMER */ |
---|
2053 | if (timint < 1) |
---|
2054 | timint = rcvtimo = 1; |
---|
2055 | msleep(50); /* Allow a bit of slop */ |
---|
2056 | x = rpack(); /* Read a packet */ |
---|
2057 | if (x == 'T' || x == 'z') /* Timed out means we're done */ |
---|
2058 | break; |
---|
2059 | xxscreen(SCR_PT,x,rsn,""); /* Let user know */ |
---|
2060 | } |
---|
2061 | xxscreen(SCR_ST,ST_MSG,0l,"Drain complete."); |
---|
2062 | } |
---|
2063 | if ((x = (what & W_KERMIT))) |
---|
2064 | xitsta |= x; /* Remember what failed. */ |
---|
2065 | success = 0; |
---|
2066 | return(y); |
---|
2067 | } |
---|
2068 | |
---|
2069 | /* scmd() -- Send a packet of the given type */ |
---|
2070 | |
---|
2071 | int |
---|
2072 | #ifdef CK_ANSIC |
---|
2073 | scmd(char t, CHAR *dat) |
---|
2074 | #else |
---|
2075 | scmd(t,dat) char t; CHAR *dat; |
---|
2076 | #endif /* CK_ANSIC */ |
---|
2077 | /* scmd */ { |
---|
2078 | int x; |
---|
2079 | extern char * srimsg; |
---|
2080 | debug(F000,"scmd",dat,t); |
---|
2081 | if (encstr(dat) < 0) { /* Encode the command string */ |
---|
2082 | srimsg = "String too long"; |
---|
2083 | return(-1); |
---|
2084 | } |
---|
2085 | x = spack(t,pktnum,size,data); |
---|
2086 | debug(F101,"scmd spack","",x); |
---|
2087 | return(x); |
---|
2088 | } |
---|
2089 | |
---|
2090 | /* Compose and Send GET packet */ |
---|
2091 | |
---|
2092 | struct opktparm { /* O-Packet item list */ |
---|
2093 | CHAR * opktitem; |
---|
2094 | struct opktparm * opktnext; |
---|
2095 | }; |
---|
2096 | |
---|
2097 | struct opktparm * opkthead = NULL; /* Linked list of O-packet fields */ |
---|
2098 | int opktcnt = 0; /* O-Packet counter */ |
---|
2099 | char * srimsg = NULL; /* GET-Packet error message */ |
---|
2100 | |
---|
2101 | /* S O P K T -- Send O-Packet */ |
---|
2102 | /* |
---|
2103 | Sends one O-Packet each time called, using first-fit method of filling |
---|
2104 | the packet from linked list of parameters pointed to by opkthead. |
---|
2105 | To be called repeatedly until list is empty or there is an error. |
---|
2106 | Returns: |
---|
2107 | -1 on failure. |
---|
2108 | 0 on success and no more fields left to send. |
---|
2109 | 1 on success but with more fields left to be sent. |
---|
2110 | */ |
---|
2111 | |
---|
2112 | int |
---|
2113 | sopkt() { |
---|
2114 | int n = 0; /* Field number in this packet */ |
---|
2115 | int rc = 0; /* Return code */ |
---|
2116 | int len = 0; /* Data field length */ |
---|
2117 | char c = NUL; |
---|
2118 | struct opktparm * o = NULL; |
---|
2119 | struct opktparm * t = NULL; |
---|
2120 | struct opktparm * prev = NULL; |
---|
2121 | CHAR * dsave = data; |
---|
2122 | int x, ssave = spsiz; |
---|
2123 | |
---|
2124 | srimsg = NULL; /* Error message */ |
---|
2125 | o = opkthead; /* Point to head of list */ |
---|
2126 | if (!o) { /* Oops, no list... */ |
---|
2127 | srimsg = "GET Packet Internal Error 1"; |
---|
2128 | debug(F100,"sopkt NULL list","",0); |
---|
2129 | return(-1); |
---|
2130 | } |
---|
2131 | while (o) { /* Go thru linked list... */ |
---|
2132 | c = *(o->opktitem); /* Parameter code */ |
---|
2133 | debug(F000,"sopkt",o->opktitem,c); |
---|
2134 | x = encstr((CHAR *)o->opktitem); |
---|
2135 | debug(F111,"sopkt encstr",dsave,x); |
---|
2136 | if (x < 0) { /* Encode this item */ |
---|
2137 | if (n == 0) { /* Failure, first field in packet */ |
---|
2138 | debug(F100,"sopkt overflow","",0); |
---|
2139 | spsiz = ssave; /* Restore these */ |
---|
2140 | data = dsave; |
---|
2141 | o = opkthead; /* Free linked list */ |
---|
2142 | while (o) { |
---|
2143 | if (o->opktitem) free(o->opktitem); |
---|
2144 | t = o->opktnext; |
---|
2145 | free((char *)o); |
---|
2146 | o = t; |
---|
2147 | } |
---|
2148 | opkthead = NULL; |
---|
2149 | srimsg = "GET Packet Too Long for Server"; |
---|
2150 | return(-1); /* Fail */ |
---|
2151 | } else { /* Not first field in packet */ |
---|
2152 | debug(F110,"sopkt leftover",o->opktitem,0); |
---|
2153 | prev = o; /* Make this one the new previous */ |
---|
2154 | o = o->opktnext; /* Get next */ |
---|
2155 | c = NUL; /* So we know we're not done */ |
---|
2156 | *data = NUL; /* Erase any partial encoding */ |
---|
2157 | continue; /* We can try this one again later */ |
---|
2158 | } |
---|
2159 | } |
---|
2160 | n++; /* Encoding was successful */ |
---|
2161 | debug(F111,"sopkt field",data,x); |
---|
2162 | len += x; /* Total data field length */ |
---|
2163 | data += x; /* Set up for next field... */ |
---|
2164 | spsiz -= x; |
---|
2165 | free(o->opktitem); /* Free item just encoded */ |
---|
2166 | if (o == opkthead) { /* If head */ |
---|
2167 | opkthead = o->opktnext; /* Move head to next */ |
---|
2168 | free((char *)o); /* Free this list node */ |
---|
2169 | o = opkthead; |
---|
2170 | } else { /* If not head */ |
---|
2171 | o = o->opktnext; /* Get next */ |
---|
2172 | prev->opktnext = o; /* Link previous to next */ |
---|
2173 | } |
---|
2174 | if (c == '@') /* Loop exit */ |
---|
2175 | break; |
---|
2176 | if (!o && !opkthead) { /* Set up End Of Parameters Field */ |
---|
2177 | o = (struct opktparm *)malloc(sizeof(struct opktparm)); |
---|
2178 | if (o) { |
---|
2179 | opkthead = o; |
---|
2180 | if (!(o->opktitem = (CHAR *)malloc(3))) { |
---|
2181 | free((char *)o); |
---|
2182 | srimsg = "GET Packet Internal Error 8"; |
---|
2183 | return(-1); |
---|
2184 | } |
---|
2185 | ckstrncpy((char *)(o->opktitem), "@ ", 3); |
---|
2186 | debug(F111,"sopkt o->opktitem",o->opktitem, |
---|
2187 | strlen((char *)(o->opktitem))); |
---|
2188 | o->opktnext = NULL; |
---|
2189 | } |
---|
2190 | } |
---|
2191 | } |
---|
2192 | data = dsave; /* Restore globals */ |
---|
2193 | spsiz = ssave; |
---|
2194 | debug(F110,"sopkt data",data,0); |
---|
2195 | debug(F101,"sopkt opktcnt","",opktcnt); |
---|
2196 | if (opktcnt++ > 0) { |
---|
2197 | if (nxtpkt() < 0) { /* Get next packet number and buffer */ |
---|
2198 | srimsg = "GET Packet Internal Error 9"; |
---|
2199 | return(-1); |
---|
2200 | } |
---|
2201 | } |
---|
2202 | debug(F101,"sopkt pktnum","",pktnum); |
---|
2203 | rc = spack((char)'O',pktnum,len,data); /* Send O-Packet */ |
---|
2204 | debug(F101,"sopkt spack","",rc); |
---|
2205 | if (rc < 0) /* Failed */ |
---|
2206 | srimsg = "Send Packet Failure"; /* Set message */ |
---|
2207 | else /* Succeeded */ |
---|
2208 | rc = (c == '@') ? 0 : 1; /* 1 = come back for more, 0 = done */ |
---|
2209 | debug(F101,"sopkt rc","",rc); |
---|
2210 | return(rc); |
---|
2211 | } |
---|
2212 | |
---|
2213 | /* S R I N I T -- Send GET packet */ |
---|
2214 | /* |
---|
2215 | Sends the appropriate GET-Class packet. |
---|
2216 | Returns: |
---|
2217 | -1 on error |
---|
2218 | 0 if packet sent successfully and we can move on to the next state |
---|
2219 | 1 if an O-packet was sent OK but more O packets still need to be sent. |
---|
2220 | */ |
---|
2221 | int |
---|
2222 | srinit(reget, retrieve, opkt) int reget, retrieve, opkt; { |
---|
2223 | int x = 0, left = 0; |
---|
2224 | extern int oopts, omode; |
---|
2225 | CHAR * p = NULL; |
---|
2226 | #ifdef RECURSIVE |
---|
2227 | extern int recursive; |
---|
2228 | debug(F101,"srinit recursive","",recursive); |
---|
2229 | #endif /* RECURSIVE */ |
---|
2230 | debug(F101,"srinit reget","",reget); |
---|
2231 | debug(F101,"srinit retrieve","",retrieve); |
---|
2232 | debug(F101,"srinit opkt","",opkt); |
---|
2233 | debug(F101,"srinit oopts","",oopts); |
---|
2234 | debug(F101,"srinit omode","",omode); |
---|
2235 | debug(F110,"srinit cmarg",cmarg,0); |
---|
2236 | srimsg = NULL; |
---|
2237 | |
---|
2238 | opktcnt = 0; |
---|
2239 | if (!cmarg) cmarg = ""; |
---|
2240 | if (!*cmarg) { |
---|
2241 | srimsg = "GET with no filename"; |
---|
2242 | debug(F100,"srinit null cmarg","",0); |
---|
2243 | return(-1); |
---|
2244 | } |
---|
2245 | if (opkt) { /* Extended GET is totally different */ |
---|
2246 | char buf[16]; |
---|
2247 | struct opktparm * o = NULL; |
---|
2248 | struct opktparm * prev = NULL; |
---|
2249 | |
---|
2250 | buf[0] = NUL; |
---|
2251 | |
---|
2252 | /* Build O-Packet fields and send (perhaps first) O-Packet */ |
---|
2253 | |
---|
2254 | if (oopts > -1) { /* Write Option flags */ |
---|
2255 | o = (struct opktparm *)malloc(sizeof(struct opktparm)); |
---|
2256 | if (!o) { |
---|
2257 | srimsg = "GET Packet Internal Error 2"; |
---|
2258 | debug(F100,"srinit malloc fail O1","",0); |
---|
2259 | return(-1); |
---|
2260 | } |
---|
2261 | sprintf(buf,"Ox%d",oopts); /* safe */ |
---|
2262 | x = (int) strlen(buf+2); |
---|
2263 | buf[1] = tochar(x); |
---|
2264 | o->opktitem = (CHAR *)malloc(x + 3); |
---|
2265 | if (!o->opktitem) { |
---|
2266 | srimsg = "GET Packet Internal Error 3"; |
---|
2267 | debug(F100,"srinit malloc fail O2","",0); |
---|
2268 | return(-1); |
---|
2269 | } |
---|
2270 | ckstrncpy((char *)(o->opktitem),buf,x+3); |
---|
2271 | o->opktnext = NULL; |
---|
2272 | if (!opkthead) |
---|
2273 | opkthead = o; |
---|
2274 | prev = o; |
---|
2275 | } |
---|
2276 | if (omode > -1) { /* If Xfer Mode specified, write it */ |
---|
2277 | o = (struct opktparm *)malloc(sizeof(struct opktparm)); |
---|
2278 | if (!o) { |
---|
2279 | srimsg = "GET Packet Internal Error 4"; |
---|
2280 | debug(F100,"srinit malloc fail M1","",0); |
---|
2281 | return(-1); |
---|
2282 | } |
---|
2283 | sprintf(buf,"Mx%d",omode); /* safe */ |
---|
2284 | x = (int) strlen(buf+2); |
---|
2285 | buf[1] = tochar(x); |
---|
2286 | o->opktitem = (CHAR *)malloc(x + 3); |
---|
2287 | if (!o->opktitem) { |
---|
2288 | srimsg = "GET Packet Internal Error 5"; |
---|
2289 | debug(F100,"srinit malloc fail O2","",0); |
---|
2290 | return(-1); |
---|
2291 | } |
---|
2292 | ckstrncpy((char *)(o->opktitem),buf,x+3); |
---|
2293 | o->opktnext = NULL; |
---|
2294 | if (!opkthead) |
---|
2295 | opkthead = o; |
---|
2296 | else |
---|
2297 | prev->opktnext = o; |
---|
2298 | prev = o; |
---|
2299 | } |
---|
2300 | |
---|
2301 | /* Same deal for oname and opath eventually but not needed now... */ |
---|
2302 | |
---|
2303 | x = strlen(cmarg); /* Now do filename */ |
---|
2304 | if (x > spsiz - 4) { |
---|
2305 | srimsg = "GET Packet Too Long for Server"; |
---|
2306 | return(-1); |
---|
2307 | } |
---|
2308 | o = (struct opktparm *)malloc(sizeof(struct opktparm)); |
---|
2309 | if (!o) { |
---|
2310 | srimsg = "GET Packet Internal Error 6"; |
---|
2311 | debug(F100,"srinit malloc fail F1","",0); |
---|
2312 | return(-1); |
---|
2313 | } |
---|
2314 | left = x + 6; |
---|
2315 | o->opktitem = (CHAR *)malloc(left + 1); |
---|
2316 | if (!o->opktitem) { |
---|
2317 | srimsg = "GET Packet Internal Error 7"; |
---|
2318 | debug(F100,"srinit malloc fail F2","",0); |
---|
2319 | return(-1); |
---|
2320 | } |
---|
2321 | p = o->opktitem; |
---|
2322 | *p++ = 'F'; |
---|
2323 | left--; |
---|
2324 | if (x > 94) { /* Too long for normal length */ |
---|
2325 | *p++ = SYN; /* Escape length with Ctrl-V */ |
---|
2326 | *p++ = tochar(x / 95); |
---|
2327 | *p++ = tochar(x % 95); |
---|
2328 | left -= 3; |
---|
2329 | } else { /* Normal encoding for 94 or less */ |
---|
2330 | *p++ = tochar(x); |
---|
2331 | left--; |
---|
2332 | } |
---|
2333 | ckstrncpy((char *)p,cmarg,left); /* Copy the filename */ |
---|
2334 | o->opktnext = NULL; |
---|
2335 | if (!opkthead) |
---|
2336 | opkthead = o; |
---|
2337 | else |
---|
2338 | prev->opktnext = o; |
---|
2339 | prev = o; |
---|
2340 | |
---|
2341 | /* End of Parameters */ |
---|
2342 | |
---|
2343 | prev->opktnext = NULL; /* End of list. */ |
---|
2344 | return(sopkt()); |
---|
2345 | } |
---|
2346 | |
---|
2347 | /* Not Extended GET */ |
---|
2348 | |
---|
2349 | if (encstr((CHAR *)cmarg) < 0) { /* Encode the filename. */ |
---|
2350 | srimsg = "GET Packet Too Long for Server"; |
---|
2351 | return(-1); |
---|
2352 | } |
---|
2353 | if (retrieve) { /* Send the packet. */ |
---|
2354 | #ifdef RECURSIVE |
---|
2355 | if (recursive) |
---|
2356 | x = spack((char)'W',pktnum,size,data); /* GET /DELETE /RECURSIVE */ |
---|
2357 | else |
---|
2358 | #endif /* RECURSIVE */ |
---|
2359 | x = spack((char)'H',pktnum,size,data); /* GET /DELETE */ |
---|
2360 | } |
---|
2361 | #ifdef RECURSIVE |
---|
2362 | else if (recursive) |
---|
2363 | x = spack((char)'V',pktnum,size,data); /* GET /RECURSIVE */ |
---|
2364 | #endif /* RECURSIVE */ |
---|
2365 | else |
---|
2366 | x = spack((char)(reget ? 'J' : 'R'),pktnum,size,data); /* GET */ |
---|
2367 | if (x < 0) |
---|
2368 | srimsg = "Send Packet Failure"; |
---|
2369 | return(x < 0 ? x : 0); |
---|
2370 | } |
---|
2371 | |
---|
2372 | |
---|
2373 | /* K S T A R T -- Checks for a Kermit packet while in terminal mode. */ |
---|
2374 | |
---|
2375 | /* (or command mode...) */ |
---|
2376 | |
---|
2377 | #ifdef CK_AUTODL |
---|
2378 | int |
---|
2379 | #ifdef CK_ANSIC |
---|
2380 | kstart(CHAR ch) |
---|
2381 | #else |
---|
2382 | kstart(ch) CHAR ch; |
---|
2383 | #endif /* CK_ANSIC */ |
---|
2384 | /* kstart */ { |
---|
2385 | static CHAR * p = NULL; |
---|
2386 | |
---|
2387 | #ifdef OS2 |
---|
2388 | static CHAR * pk = NULL; |
---|
2389 | #endif /* OS2 */ |
---|
2390 | ch &= 0177; /* Strip 8th bit */ |
---|
2391 | |
---|
2392 | /* Because we're in cooked mode at the command prompt... */ |
---|
2393 | |
---|
2394 | if (ch == LF) { |
---|
2395 | debug(F110,"kstart","ch == LF",0); |
---|
2396 | if ((what == W_COMMAND || what == W_INIT || what == W_NOTHING)) { |
---|
2397 | if (eol == CR) { |
---|
2398 | ch = eol; |
---|
2399 | debug(F110,"kstart","ch = CR",0); |
---|
2400 | } |
---|
2401 | } |
---|
2402 | } |
---|
2403 | |
---|
2404 | #ifdef OS2 |
---|
2405 | if (adl_kmode == ADL_STR) { |
---|
2406 | if (!ch) |
---|
2407 | return(0); |
---|
2408 | if (!pk) |
---|
2409 | pk = adl_kstr; |
---|
2410 | |
---|
2411 | if (ch == *pk) { |
---|
2412 | pk++; |
---|
2413 | if (*pk == '\0') { |
---|
2414 | pk = adl_kstr; |
---|
2415 | debug(F100, "kstart Kermit Start String","",0); |
---|
2416 | return(PROTO_K + 1); |
---|
2417 | } |
---|
2418 | } else |
---|
2419 | pk = adl_kstr; |
---|
2420 | } |
---|
2421 | #endif /* OS2 */ |
---|
2422 | |
---|
2423 | if (ch == stchr) { /* Start of packet */ |
---|
2424 | kstartactive = 1; |
---|
2425 | p = ksbuf; |
---|
2426 | *p = ch; |
---|
2427 | debug(F101,"kstart SOP","",ch); |
---|
2428 | } else if (ch == eol) { /* End of packet */ |
---|
2429 | kstartactive = 0; |
---|
2430 | if (p) { |
---|
2431 | debug(F101,"kstart EOL","",ch); |
---|
2432 | p++; |
---|
2433 | if (p - ksbuf < 94 ) { |
---|
2434 | int rc = 0; |
---|
2435 | *p++ = ch; |
---|
2436 | *p = NUL; |
---|
2437 | rc = chkspkt((char *)ksbuf); |
---|
2438 | debug(F111,"kstart EOP chkspkt", ksbuf, rc); |
---|
2439 | p = NULL; |
---|
2440 | if (!rc) return(0); |
---|
2441 | if (rc == 2) rc = -1; |
---|
2442 | debug(F111,"kstart ksbuf",ksbuf,rc); |
---|
2443 | return(rc); |
---|
2444 | } else { |
---|
2445 | debug(F110,"kstart","p - ksbuf >= 94",0); |
---|
2446 | p = NULL; |
---|
2447 | } |
---|
2448 | } |
---|
2449 | } else if (p) { |
---|
2450 | if (ch < SP) |
---|
2451 | kstartactive = 0; |
---|
2452 | p++; |
---|
2453 | if (p - ksbuf < 94) { |
---|
2454 | *p = ch; |
---|
2455 | } else { |
---|
2456 | p = NULL; |
---|
2457 | debug(F110,"kstart","p - ksbuf >= 94",0); |
---|
2458 | } |
---|
2459 | } |
---|
2460 | return(0); |
---|
2461 | } |
---|
2462 | |
---|
2463 | #ifdef CK_XYZ |
---|
2464 | |
---|
2465 | /* Z S T A R T -- Checks for a ZMODEM packet while in terminal mode. */ |
---|
2466 | |
---|
2467 | int |
---|
2468 | #ifdef CK_ANSIC |
---|
2469 | zstart(CHAR ch) |
---|
2470 | #else |
---|
2471 | zstart(ch) CHAR ch; |
---|
2472 | #endif /* CK_ANSIC */ |
---|
2473 | /* zstart */ { |
---|
2474 | static CHAR * matchstr = (CHAR *) "\030B00"; |
---|
2475 | /* "rz\r**\030B00000000000000\r\033J\021"; */ |
---|
2476 | static CHAR * p = NULL; |
---|
2477 | extern int inserver; |
---|
2478 | |
---|
2479 | if (inserver) |
---|
2480 | return(0); |
---|
2481 | |
---|
2482 | if (!ch) |
---|
2483 | return(0); |
---|
2484 | if (!p) { |
---|
2485 | #ifdef OS2 |
---|
2486 | p = adl_zmode == ADL_PACK ? matchstr : adl_zstr; |
---|
2487 | #else |
---|
2488 | p = matchstr; |
---|
2489 | #endif /* OS2 */ |
---|
2490 | } |
---|
2491 | if (ch == *p) { |
---|
2492 | p++; |
---|
2493 | if (*p == '\0') { |
---|
2494 | #ifdef OS2 |
---|
2495 | if (adl_zmode == ADL_PACK) { |
---|
2496 | p = matchstr; |
---|
2497 | debug(F100, "zstart Zmodem SOP","",0); |
---|
2498 | } else { |
---|
2499 | p = adl_zstr; |
---|
2500 | debug(F100, "zstart Zmodem Start String","",0); |
---|
2501 | } |
---|
2502 | #else |
---|
2503 | p = matchstr; |
---|
2504 | debug(F100, "zstart Zmodem SOP","",0); |
---|
2505 | #endif /* OS2 */ |
---|
2506 | return(PROTO_Z + 1); |
---|
2507 | } |
---|
2508 | } else { |
---|
2509 | #ifdef OS2 |
---|
2510 | p = adl_zmode == ADL_PACK ? matchstr : adl_zstr; |
---|
2511 | #else |
---|
2512 | p = matchstr; |
---|
2513 | #endif /* OS2 */ |
---|
2514 | } |
---|
2515 | return(0); |
---|
2516 | } |
---|
2517 | #endif /* CK_XYZ */ |
---|
2518 | |
---|
2519 | #ifndef NOICP |
---|
2520 | #ifdef CK_APC |
---|
2521 | /* A U T O D O W N */ |
---|
2522 | |
---|
2523 | #ifdef CK_ANSIC |
---|
2524 | VOID |
---|
2525 | autodown(int ch) |
---|
2526 | #else |
---|
2527 | VOID |
---|
2528 | autodown(ch) int ch; |
---|
2529 | #endif /* CK_ANSIC */ |
---|
2530 | /* autodown */ { |
---|
2531 | |
---|
2532 | /* The Kermit and Zmodem Auto-download calls go here */ |
---|
2533 | |
---|
2534 | extern int justone; /* From protocol module */ |
---|
2535 | extern int debses, protocol, apcactive, autodl, inautodl; |
---|
2536 | #ifdef DCMDBUF |
---|
2537 | extern char *apcbuf; |
---|
2538 | #else |
---|
2539 | extern char apcbuf[]; |
---|
2540 | #endif /* DCMDBUF */ |
---|
2541 | #ifdef OS2 |
---|
2542 | extern int apclength, term_io; |
---|
2543 | #endif /* OS2 */ |
---|
2544 | int k = 0; |
---|
2545 | |
---|
2546 | if ((autodl || inautodl |
---|
2547 | #ifdef IKS_OPTION |
---|
2548 | || TELOPT_SB(TELOPT_KERMIT).kermit.me_start |
---|
2549 | #endif /* IKS_OPTION */ |
---|
2550 | ) && !debses) { |
---|
2551 | #ifdef CK_XYZ |
---|
2552 | #ifdef XYZ_INTERNAL |
---|
2553 | extern int p_avail; |
---|
2554 | #else |
---|
2555 | int p_avail = 1; |
---|
2556 | #endif /* XYZ_INTERNAL */ |
---|
2557 | if (p_avail && zstart((CHAR) ch)) { |
---|
2558 | debug(F100, "Zmodem download","",0); |
---|
2559 | #ifdef OS2 |
---|
2560 | #ifndef NOTERM |
---|
2561 | apc_command(APC_LOCAL,"receive /protocol:zmodem"); |
---|
2562 | #endif /* NOTERM */ |
---|
2563 | #else /* OS2 */ |
---|
2564 | ckstrncpy(apcbuf,"receive /protocol:zmodem",APCBUFLEN); |
---|
2565 | apcactive = APC_LOCAL; |
---|
2566 | #endif /* OS2 */ |
---|
2567 | return; |
---|
2568 | } |
---|
2569 | #endif /* CK_XYZ */ |
---|
2570 | |
---|
2571 | /* First try... */ |
---|
2572 | k = kstart((CHAR) ch); |
---|
2573 | if ( |
---|
2574 | #ifdef NOSERVER |
---|
2575 | k > 0 |
---|
2576 | #else /* NOSERVER */ |
---|
2577 | k |
---|
2578 | #endif /* NOSERVER */ |
---|
2579 | ) { /* We saw a valid S or I packet */ |
---|
2580 | if (k < 0) { /* Stuff RECEIVE into APC buffer */ |
---|
2581 | justone = 1; |
---|
2582 | switch (protocol) { |
---|
2583 | #ifdef CK_XYZ |
---|
2584 | case PROTO_G: |
---|
2585 | ckstrncpy(apcbuf, |
---|
2586 | "set proto kermit, server, set protocol g", |
---|
2587 | APCBUFLEN |
---|
2588 | ); |
---|
2589 | break; |
---|
2590 | case PROTO_X: |
---|
2591 | ckstrncpy(apcbuf, |
---|
2592 | "set proto kermit,server,set proto xmodem", |
---|
2593 | APCBUFLEN |
---|
2594 | ); |
---|
2595 | break; |
---|
2596 | case PROTO_XC: |
---|
2597 | ckstrncpy(apcbuf, |
---|
2598 | "set proto kermit,server,set proto xmodem-crc", |
---|
2599 | APCBUFLEN |
---|
2600 | ); |
---|
2601 | break; |
---|
2602 | case PROTO_Y: |
---|
2603 | ckstrncpy(apcbuf, |
---|
2604 | "set proto kermit,server, set protocol y", |
---|
2605 | APCBUFLEN |
---|
2606 | ); |
---|
2607 | break; |
---|
2608 | case PROTO_Z: |
---|
2609 | ckstrncpy(apcbuf, |
---|
2610 | "set proto kermit,server,set proto zmodem", |
---|
2611 | APCBUFLEN |
---|
2612 | ); |
---|
2613 | break; |
---|
2614 | #endif /* CK_XYZ */ |
---|
2615 | case PROTO_K: |
---|
2616 | ckstrncpy(apcbuf,"server",APCBUFLEN); |
---|
2617 | break; |
---|
2618 | } |
---|
2619 | } else { |
---|
2620 | justone = 0; |
---|
2621 | ckstrncpy(apcbuf,"receive /protocol:kermit",APCBUFLEN); |
---|
2622 | } |
---|
2623 | #ifdef OS2 |
---|
2624 | #ifndef NOTERM |
---|
2625 | apc_command(APC_LOCAL,apcbuf); |
---|
2626 | #endif /* NOTERM */ |
---|
2627 | #else /* OS2 */ |
---|
2628 | ckstrncpy(apcbuf,"receive /protocol:zmodem",APCBUFLEN); |
---|
2629 | apcactive = APC_LOCAL; |
---|
2630 | #endif /* OS2 */ |
---|
2631 | return; |
---|
2632 | } |
---|
2633 | } |
---|
2634 | } |
---|
2635 | #endif /* CK_APC */ |
---|
2636 | #endif /* NOICP */ |
---|
2637 | |
---|
2638 | /* C H K S P K T -- Check if buf contains a valid S or I packet */ |
---|
2639 | |
---|
2640 | int |
---|
2641 | chkspkt(buf) char *buf; { |
---|
2642 | int buflen; |
---|
2643 | int len = -1; |
---|
2644 | CHAR chk; |
---|
2645 | char type = 0; |
---|
2646 | char *s = buf; |
---|
2647 | |
---|
2648 | if (!buf) return(0); |
---|
2649 | buflen = strlen(buf); |
---|
2650 | if (buflen < 5) return(0); /* Too short */ |
---|
2651 | if (*s++ != stchr) return(0); /* SOH */ |
---|
2652 | len = xunchar(*s++); /* Length */ |
---|
2653 | if (len < 0) return(0); |
---|
2654 | if (*s++ != SP) return(0); /* Sequence number */ |
---|
2655 | type = *s++; /* Type */ |
---|
2656 | if (type != 'S' && type != 'I') |
---|
2657 | return(0); |
---|
2658 | if (buflen < len + 2) return(0); |
---|
2659 | s += (len - 3); /* Position of checksum */ |
---|
2660 | chk = (CHAR) (*s); /* Checksum */ |
---|
2661 | *s = NUL; |
---|
2662 | if (xunchar(chk) != chk1((CHAR *)(buf+1),buflen-2)) /* Check it */ |
---|
2663 | return(0); |
---|
2664 | *s = chk; |
---|
2665 | return(type == 'S' ? 1 : 2); |
---|
2666 | } |
---|
2667 | #endif /* CK_AUTODL */ |
---|
2668 | |
---|
2669 | /* R P A C K -- Read a Packet */ |
---|
2670 | |
---|
2671 | /* |
---|
2672 | rpack reads a packet and returns the packet type, or else Q if the |
---|
2673 | packet was invalid, or T if a timeout occurred. Upon successful return, |
---|
2674 | sets the values of global rsn (received sequence number), rln (received |
---|
2675 | data length), and rdatap (pointer to null-terminated data field), and |
---|
2676 | returns the packet type. NOTE: This is an inner-loop function so must be |
---|
2677 | efficient. Protect function calls by if-tests where possible, e.g. |
---|
2678 | "if (pktlog) logpkt(...);". |
---|
2679 | */ |
---|
2680 | int |
---|
2681 | rpack() { |
---|
2682 | register int i, j, x, lp; /* Local variables */ |
---|
2683 | #ifdef CKTUNING |
---|
2684 | unsigned int chk; |
---|
2685 | #endif /* CKTUNING */ |
---|
2686 | int k, type, chklen; |
---|
2687 | unsigned crc; |
---|
2688 | CHAR pbc[5]; /* Packet block check */ |
---|
2689 | CHAR *sohp; /* Pointer to SOH */ |
---|
2690 | CHAR e; /* Packet end character */ |
---|
2691 | |
---|
2692 | #ifdef GFTIMER |
---|
2693 | CKFLOAT t1 = 0.0, t2 = 0.0; |
---|
2694 | #endif /* GFTIMER */ |
---|
2695 | |
---|
2696 | debug(F101,"rpack pktnum","",pktnum); |
---|
2697 | |
---|
2698 | #ifndef OLDCHKINT |
---|
2699 | if (chkint() < 0) /* Check for console interrupts. */ |
---|
2700 | return('z'); |
---|
2701 | #endif /* OLDCHKINT */ |
---|
2702 | |
---|
2703 | k = getrbuf(); /* Get a new packet input buffer. */ |
---|
2704 | debug(F101,"rpack getrbuf","",k); |
---|
2705 | if (k < 0) { /* Return like this if none free. */ |
---|
2706 | return(-1); |
---|
2707 | } |
---|
2708 | recpkt = r_pkt[k].bf_adr; |
---|
2709 | *recpkt = '\0'; /* Clear receive buffer. */ |
---|
2710 | sohp = recpkt; /* Initialize pointers to it. */ |
---|
2711 | rdatap = recpkt; |
---|
2712 | rsn = rln = -1; /* In case of failure. */ |
---|
2713 | e = (turn) ? turnch : eol; /* Use any handshake char for eol */ |
---|
2714 | |
---|
2715 | /* Try to get a "line". */ |
---|
2716 | |
---|
2717 | #ifdef CK_AUTODL |
---|
2718 | debug(F110,"rpack ksbuf",ksbuf,0); |
---|
2719 | if (ksbuf[0]) { /* Kermit packet already */ |
---|
2720 | int x; /* collected for us in CONNECT mode */ |
---|
2721 | CHAR *s1 = recpkt, *s2 = ksbuf; |
---|
2722 | j = 0; |
---|
2723 | while (*s2) { /* Copy and get length */ |
---|
2724 | *s1++ = *s2++; /* No point optimizing this since */ |
---|
2725 | j++; /* it's never more than ~20 chars */ |
---|
2726 | } |
---|
2727 | *s1 = NUL; |
---|
2728 | #ifdef PARSENSE |
---|
2729 | x = parchk(recpkt, stchr, j); /* Check parity */ |
---|
2730 | debug(F000,"autodownload parity","",parity); |
---|
2731 | debug(F000,"autodownload parchk","",x); |
---|
2732 | if (x > -1 && parity != x) { |
---|
2733 | autopar = 1; |
---|
2734 | parity = x; |
---|
2735 | } |
---|
2736 | #endif /* PARSENSE */ |
---|
2737 | ksbuf[0] = NUL; /* Don't do this next time! */ |
---|
2738 | |
---|
2739 | } else { /* Normally go read a packet */ |
---|
2740 | #endif /* CK_AUTODL */ |
---|
2741 | |
---|
2742 | #ifdef DEBUG |
---|
2743 | if (deblog) { |
---|
2744 | debug(F101,"rpack timint","",timint); |
---|
2745 | debug(F101,"rpack rcvtimo","",rcvtimo); |
---|
2746 | #ifdef STREAMING |
---|
2747 | debug(F101,"rpack streaming","",streaming); |
---|
2748 | #endif /* STREAMING */ |
---|
2749 | #ifdef GFTIMER |
---|
2750 | /* Measure how long it takes to read a packet */ |
---|
2751 | t1 = gftimer(); |
---|
2752 | #endif /* GFTIMER */ |
---|
2753 | } |
---|
2754 | #endif /* DEBUG */ |
---|
2755 | |
---|
2756 | /* JUST IN CASE (otherwise this could clobber streaming) */ |
---|
2757 | |
---|
2758 | if ((timint == 0 |
---|
2759 | #ifdef STREAMING |
---|
2760 | || streaming |
---|
2761 | #endif /* STREAMING */ |
---|
2762 | ) && (rcvtimo != 0)) { |
---|
2763 | debug(F101,"rpack timint 0 || streaming but rcvtimo","",rcvtimo); |
---|
2764 | rcvtimo = 0; |
---|
2765 | } |
---|
2766 | |
---|
2767 | #ifdef PARSENSE |
---|
2768 | #ifdef UNIX |
---|
2769 | /* |
---|
2770 | So far the final turn argument is only for ck[uvdl]tio.c. Should be added |
---|
2771 | to the others too. (turn == handshake character.) |
---|
2772 | */ |
---|
2773 | j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn); |
---|
2774 | #else |
---|
2775 | #ifdef VMS |
---|
2776 | j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn); |
---|
2777 | #else |
---|
2778 | #ifdef datageneral |
---|
2779 | j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn); |
---|
2780 | #else |
---|
2781 | #ifdef STRATUS |
---|
2782 | j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn); |
---|
2783 | #else |
---|
2784 | #ifdef OS2 |
---|
2785 | j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn); |
---|
2786 | #else |
---|
2787 | #ifdef OSK |
---|
2788 | j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr,turn); |
---|
2789 | #else |
---|
2790 | j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e,stchr); |
---|
2791 | #endif /* OSK */ |
---|
2792 | #endif /* OS2 */ |
---|
2793 | #endif /* STRATUS */ |
---|
2794 | #endif /* datageneral */ |
---|
2795 | #endif /* VMS */ |
---|
2796 | #endif /* UNIX */ |
---|
2797 | if (parity != 0 && parity != 's' && ttprty != 0) { |
---|
2798 | if (parity != ttprty) autopar = 1; |
---|
2799 | parity = ttprty; |
---|
2800 | } |
---|
2801 | #else /* !PARSENSE */ |
---|
2802 | j = ttinl(recpkt,r_pkt[k].bf_len - 1,rcvtimo,e); |
---|
2803 | #endif /* PARSENSE */ |
---|
2804 | |
---|
2805 | #ifdef DEBUG |
---|
2806 | if (deblog) { |
---|
2807 | debug(F101,"rpack ttinl len","",j); |
---|
2808 | #ifdef GFTIMER |
---|
2809 | t2 = gftimer(); |
---|
2810 | debug(F101,"rpack ttinl msec","",(long)((t2-t1)*1000.0)); |
---|
2811 | #endif /* GFTIMER */ |
---|
2812 | } |
---|
2813 | #endif /* DEBUG */ |
---|
2814 | |
---|
2815 | #ifdef STREAMING |
---|
2816 | if (streaming && sndtyp == 'D' && j == 0) |
---|
2817 | return('Y'); |
---|
2818 | #endif /* STREAMING */ |
---|
2819 | |
---|
2820 | if (j < 0) { |
---|
2821 | /* -1 == timeout, -2 == ^C, -3 == connection lost or fatal i/o */ |
---|
2822 | debug(F101,"rpack: ttinl fails","",j); /* Otherwise, */ |
---|
2823 | freerbuf(k); /* Free this buffer */ |
---|
2824 | if (j < -1) { /* Bail out if ^C^C typed. */ |
---|
2825 | if (j == -2) { |
---|
2826 | interrupted = 1; |
---|
2827 | debug(F101,"rpack ^C server","",server); |
---|
2828 | debug(F101,"rpack ^C en_fin","",en_fin); |
---|
2829 | } else if (j == -3) { |
---|
2830 | fatalio = 1; |
---|
2831 | debug(F101,"rpack fatalio","",en_fin); |
---|
2832 | } |
---|
2833 | return(j); |
---|
2834 | } |
---|
2835 | if (nakstate) /* j == -1 is a read timeout */ |
---|
2836 | xxscreen(SCR_PT,'T',(long)winlo,""); |
---|
2837 | else |
---|
2838 | xxscreen(SCR_PT,'T',(long)pktnum,""); |
---|
2839 | logpkt('r',-1,(CHAR *)"<timeout>",0); |
---|
2840 | if (flow == 1) ttoc(XON); /* In case of Xoff blockage. */ |
---|
2841 | return('T'); |
---|
2842 | } |
---|
2843 | #ifdef CK_AUTODL |
---|
2844 | } |
---|
2845 | #endif /* CK_AUTODL */ |
---|
2846 | |
---|
2847 | rpktl = j; |
---|
2848 | tlci += j; /* All OK, Count the characters. */ |
---|
2849 | flci += j; |
---|
2850 | |
---|
2851 | /* Find start of packet */ |
---|
2852 | |
---|
2853 | #ifndef PARSENSE |
---|
2854 | for (i = 0; (recpkt[i] != stchr) && (i < j); i++) |
---|
2855 | sohp++; /* Find mark */ |
---|
2856 | if (i++ >= j) { /* Didn't find it. */ |
---|
2857 | logpkt('r',-1,"<timeout>",0); |
---|
2858 | freerbuf(k); |
---|
2859 | return('T'); |
---|
2860 | } |
---|
2861 | #else |
---|
2862 | i = 1; /* ttinl does this for us */ |
---|
2863 | #endif /* PARSENSE */ |
---|
2864 | |
---|
2865 | rpackets++; /* Count received packet. */ |
---|
2866 | lp = i; /* Remember LEN position. */ |
---|
2867 | if ((j = xunchar(recpkt[i++])) == 0) { /* Get packet length. */ |
---|
2868 | if ((j = lp+5) > MAXRP) { /* Long packet */ |
---|
2869 | return('Q'); /* Too long */ |
---|
2870 | } |
---|
2871 | |
---|
2872 | #ifdef CKTUNING |
---|
2873 | /* Save some function-call and loop overhead... */ |
---|
2874 | #ifdef COMMENT |
---|
2875 | /* ttinl() already removed parity */ |
---|
2876 | if (parity) |
---|
2877 | #endif /* COMMENT */ |
---|
2878 | chk = (unsigned) ((unsigned) recpkt[i-1] + |
---|
2879 | (unsigned) recpkt[i] + |
---|
2880 | (unsigned) recpkt[i+1] + |
---|
2881 | (unsigned) recpkt[i+2] + |
---|
2882 | (unsigned) recpkt[i+3] |
---|
2883 | ); |
---|
2884 | #ifdef COMMENT |
---|
2885 | else |
---|
2886 | chk = (unsigned) ((unsigned) (recpkt[i-1] & 077) + |
---|
2887 | (unsigned) (recpkt[i] & 077) + |
---|
2888 | (unsigned) (recpkt[i+1] & 077) + |
---|
2889 | (unsigned) (recpkt[i+2] & 077) + |
---|
2890 | (unsigned) (recpkt[i+3] & 077) |
---|
2891 | ); |
---|
2892 | #endif /* COMMENT */ |
---|
2893 | if (xunchar(recpkt[j]) != ((((chk & 0300) >> 6) + chk) & 077)) |
---|
2894 | #else |
---|
2895 | x = recpkt[j]; /* Header checksum. */ |
---|
2896 | recpkt[j] = '\0'; /* Calculate & compare. */ |
---|
2897 | if (xunchar(x) != chk1(recpkt+lp,5)) |
---|
2898 | #endif /* CKTUNING */ |
---|
2899 | { |
---|
2900 | freerbuf(k); |
---|
2901 | logpkt('r',-1,(CHAR *)"<crunched:hdr>",0); |
---|
2902 | xxscreen(SCR_PT,'%',(long)pktnum,"Bad packet header"); |
---|
2903 | return('Q'); |
---|
2904 | } |
---|
2905 | #ifndef CKTUNING |
---|
2906 | recpkt[j] = x; /* Checksum ok, put it back. */ |
---|
2907 | #endif /* CKTUNING */ |
---|
2908 | rln = xunchar(recpkt[j-2]) * 95 + xunchar(recpkt[j-1]) - bctl; |
---|
2909 | j = 3; /* Data offset. */ |
---|
2910 | } else if (j < 3) { |
---|
2911 | debug(F101,"rpack packet length less than 3","",j); |
---|
2912 | freerbuf(k); |
---|
2913 | logpkt('r',-1,(CHAR *)"<crunched:len>",0); |
---|
2914 | xxscreen(SCR_PT,'%',(long)pktnum,"Bad packet length"); |
---|
2915 | return('Q'); |
---|
2916 | } else { |
---|
2917 | rln = j - bctl - 2; /* Regular packet */ |
---|
2918 | j = 0; /* No extended header */ |
---|
2919 | } |
---|
2920 | rsn = xunchar(recpkt[i++]); /* Sequence number */ |
---|
2921 | if (pktlog) /* Save a function call! */ |
---|
2922 | logpkt('r',rsn,sohp,rln+bctl+j+4); |
---|
2923 | if (rsn < 0 || rsn > 63) { |
---|
2924 | debug(F101,"rpack bad sequence number","",rsn); |
---|
2925 | freerbuf(k); |
---|
2926 | if (pktlog) |
---|
2927 | logpkt('r',rsn,(CHAR *)"<crunched:seq>",0); |
---|
2928 | xxscreen(SCR_PT,'%',(long)pktnum,"Bad sequence number"); |
---|
2929 | return('Q'); |
---|
2930 | } |
---|
2931 | /* |
---|
2932 | If this packet has the same type as the packet just sent, assume it is |
---|
2933 | an echo and ignore it. Don't even bother with the block check calculation: |
---|
2934 | even if the packet is corrupted, we don't want to NAK an echoed packet. |
---|
2935 | Nor must we NAK an ACK or NAK. |
---|
2936 | */ |
---|
2937 | type = recpkt[i++]; /* Get packet's TYPE field */ |
---|
2938 | if (type == sndtyp || (nakstate && (type == 'N' /* || type == 'Y' */ ))) { |
---|
2939 | debug(F000,"rpack echo","",type); /* If it's an echo */ |
---|
2940 | freerbuf(k); /* Free this buffer */ |
---|
2941 | logpkt('#',rsn,(CHAR *)"<echo:ignored>",0); |
---|
2942 | return('e'); /* Return special (lowercase) code */ |
---|
2943 | } |
---|
2944 | /* |
---|
2945 | Separate the data from the block check, accounting for the case where |
---|
2946 | a packet was retransmitted after the block check switched. |
---|
2947 | */ |
---|
2948 | if (type == 'I' || type == 'S') { /* I & S packets always have type 1 */ |
---|
2949 | chklen = 1; |
---|
2950 | rln = rln + bctl - 1; |
---|
2951 | } else if (type == 'N') { /* A NAK packet never has data */ |
---|
2952 | chklen = xunchar(recpkt[lp]) - 2; |
---|
2953 | rln = rln + bctl - chklen; |
---|
2954 | } else chklen = bctl; |
---|
2955 | #ifdef DEBUG |
---|
2956 | if (deblog) { /* Save 2 function calls */ |
---|
2957 | debug(F101,"rpack bctl","",bctl); |
---|
2958 | debug(F101,"rpack chklen","",chklen); |
---|
2959 | } |
---|
2960 | #endif /* DEBUG */ |
---|
2961 | i += j; /* Buffer index of DATA field */ |
---|
2962 | rdatap = recpkt+i; /* Pointer to DATA field */ |
---|
2963 | if ((j = rln + i) > r_pkt[k].bf_len) { /* Make sure it fits */ |
---|
2964 | debug(F101,"packet too long","",j); |
---|
2965 | freerbuf(k); |
---|
2966 | logpkt('r',rsn,(CHAR *)"<overflow>",0); |
---|
2967 | return('Q'); |
---|
2968 | } |
---|
2969 | for (x = 0; x < chklen; x++) /* Copy the block check */ |
---|
2970 | pbc[x] = recpkt[j+x]; /* 3 bytes at most. */ |
---|
2971 | pbc[x] = '\0'; /* Null-terminate block check string */ |
---|
2972 | recpkt[j] = '\0'; /* and the packet Data field. */ |
---|
2973 | |
---|
2974 | if (chklen == 2 && bctu == 4) { /* Adjust for Blank-Free-2 */ |
---|
2975 | chklen = 4; /* (chklen is now a misnomer...) */ |
---|
2976 | debug(F100,"rpack block check B","",0); |
---|
2977 | } |
---|
2978 | switch (chklen) { /* Check the block check */ |
---|
2979 | case 1: /* Type 1, 6-bit checksum */ |
---|
2980 | if (xunchar(*pbc) != chk1(recpkt+lp,j-lp)) { |
---|
2981 | #ifdef DEBUG |
---|
2982 | if (deblog) { |
---|
2983 | debug(F110,"checked chars",recpkt+lp,0); |
---|
2984 | debug(F101,"block check (1)","",(int) xunchar(*pbc)); |
---|
2985 | debug(F101,"should be (1)","",chk1(recpkt+lp,j-lp)); |
---|
2986 | } |
---|
2987 | #endif /* DEBUG */ |
---|
2988 | freerbuf(k); |
---|
2989 | logpkt('r',-1,(CHAR *)"<crunched:chk1>",0); |
---|
2990 | xxscreen(SCR_PT,'%',(long)pktnum,"Checksum error"); |
---|
2991 | return('Q'); |
---|
2992 | } |
---|
2993 | break; |
---|
2994 | case 2: /* Type 2, 12-bit checksum */ |
---|
2995 | x = xunchar(*pbc) << 6 | xunchar(pbc[1]); |
---|
2996 | if (x != chk2(recpkt+lp,j-lp)) { /* No match */ |
---|
2997 | if (type == 'E') { /* Allow E packets to have type 1 */ |
---|
2998 | recpkt[j++] = pbc[0]; |
---|
2999 | recpkt[j] = '\0'; |
---|
3000 | if (xunchar(pbc[1]) == chk1(recpkt+lp,j-lp)) |
---|
3001 | break; |
---|
3002 | else |
---|
3003 | recpkt[--j] = '\0'; |
---|
3004 | } |
---|
3005 | #ifdef DEBUG |
---|
3006 | if (deblog) { |
---|
3007 | debug(F110,"checked chars",recpkt+lp,0); |
---|
3008 | debug(F101,"block check (2)","", x); |
---|
3009 | debug(F101,"should be (2)","", (int) chk2(recpkt+lp,j-lp)); |
---|
3010 | } |
---|
3011 | #endif /* DEBUG */ |
---|
3012 | freerbuf(k); |
---|
3013 | logpkt('r',-1,(CHAR *)"<crunched:chk2>",0); |
---|
3014 | xxscreen(SCR_PT,'%',(long)pktnum,"Checksum error"); |
---|
3015 | return('Q'); |
---|
3016 | } |
---|
3017 | break; |
---|
3018 | case 3: /* Type 3, 16-bit CRC */ |
---|
3019 | crc = (xunchar(pbc[0]) << 12) |
---|
3020 | | (xunchar(pbc[1]) << 6) |
---|
3021 | | (xunchar(pbc[2])); |
---|
3022 | if (crc != chk3(recpkt+lp,j-lp)) { |
---|
3023 | if (type == 'E') { /* Allow E packets to have type 1 */ |
---|
3024 | recpkt[j++] = pbc[0]; |
---|
3025 | recpkt[j++] = pbc[1]; |
---|
3026 | recpkt[j] = '\0'; |
---|
3027 | if (xunchar(pbc[2]) == chk1(recpkt+lp,j-lp)) |
---|
3028 | break; |
---|
3029 | else { j -=2; recpkt[j] = '\0'; } |
---|
3030 | } |
---|
3031 | #ifdef DEBUG |
---|
3032 | if (deblog) { |
---|
3033 | debug(F110,"checked chars",recpkt+lp,0); |
---|
3034 | debug(F101,"block check (3)","",crc); |
---|
3035 | debug(F101,"should be (3)","",(int) chk3(recpkt+lp,j-lp)); |
---|
3036 | } |
---|
3037 | #endif /* DEBUG */ |
---|
3038 | freerbuf(k); |
---|
3039 | logpkt('r',-1,(CHAR *)"<crunched:chk3>",0); |
---|
3040 | xxscreen(SCR_PT,'%',(long)pktnum,"CRC error"); |
---|
3041 | return('Q'); |
---|
3042 | } |
---|
3043 | break; |
---|
3044 | case 4: /* Type 4 = Type 2, no blanks. */ |
---|
3045 | x = (unsigned)((xunchar(*pbc) - 1) << 6) | |
---|
3046 | (unsigned)(xunchar(pbc[1]) - 1); |
---|
3047 | if (x != chk2(recpkt+lp,j-lp)) { |
---|
3048 | if (type == 'E') { /* Allow E packets to have type 1 */ |
---|
3049 | recpkt[j++] = pbc[0]; |
---|
3050 | recpkt[j] = '\0'; |
---|
3051 | if (xunchar(pbc[1]) == chk1(recpkt+lp,j-lp)) |
---|
3052 | break; |
---|
3053 | else |
---|
3054 | recpkt[--j] = '\0'; |
---|
3055 | } |
---|
3056 | debug(F101,"bad type B block check","",x); |
---|
3057 | freerbuf(k); |
---|
3058 | logpkt('r',-1,(CHAR *)"<crunched:chkb>",0); |
---|
3059 | xxscreen(SCR_PT,'%',(long)pktnum,"Checksum error"); |
---|
3060 | return('Q'); |
---|
3061 | } |
---|
3062 | break; |
---|
3063 | default: /* Shouldn't happen... */ |
---|
3064 | freerbuf(k); |
---|
3065 | logpkt('r',-1,(CHAR *)"<crunched:chkx>",0); |
---|
3066 | xxscreen(SCR_PT,'%',(long)pktnum,"(crunched)"); |
---|
3067 | return('Q'); |
---|
3068 | } |
---|
3069 | debug(F101,"rpack block check OK","",rsn); |
---|
3070 | |
---|
3071 | /* Now we can believe the sequence number, and other fields. */ |
---|
3072 | /* Here we violate strict principles of layering, etc, and look at the */ |
---|
3073 | /* packet sequence number. If there's already a packet with the same */ |
---|
3074 | /* number in the window, we remove this one so that the window will not */ |
---|
3075 | /* fill up. */ |
---|
3076 | |
---|
3077 | if ((x = rseqtbl[rsn]) != -1) { /* Already a packet with this number */ |
---|
3078 | retrans++; /* Count it for statistics */ |
---|
3079 | debug(F101,"rpack got dup","",rsn); |
---|
3080 | logpkt('r',rsn,(CHAR *)"<duplicate>",0); |
---|
3081 | freerbuf(x); /* Free old buffer, keep new packet. */ |
---|
3082 | r_pkt[k].pk_rtr++; /* Count this as a retransmission. */ |
---|
3083 | } |
---|
3084 | |
---|
3085 | /* New packet, not seen before, enter it into the receive window. */ |
---|
3086 | |
---|
3087 | #ifdef CK_TIMERS |
---|
3088 | if (timint > 0) |
---|
3089 | rrttbl[rsn] = gtimer(); /* Timestamp */ |
---|
3090 | #endif /* CK_TIMERS */ |
---|
3091 | |
---|
3092 | rseqtbl[rsn] = k; /* Make back pointer */ |
---|
3093 | r_pkt[k].pk_seq = rsn; /* Record in packet info structure */ |
---|
3094 | r_pkt[k].pk_typ = type; /* Sequence, type,... */ |
---|
3095 | r_pkt[k].pk_adr = rdatap; /* pointer to data buffer */ |
---|
3096 | if (local) { /* Save a function call! */ |
---|
3097 | int x = 0; |
---|
3098 | if (fdispla != XYFD_N) x = 1; |
---|
3099 | if (fdispla == XYFD_B && (type == 'D' || sndtyp == 'D')) x = 0; |
---|
3100 | if (x) /* Update screen */ |
---|
3101 | xxscreen(SCR_PT,(char)type,(long)rsn,(char *)sohp); |
---|
3102 | } |
---|
3103 | return(type); /* Return packet type */ |
---|
3104 | } |
---|
3105 | |
---|
3106 | /* L O G P K T -- Log packet number n, pointed to by s. */ |
---|
3107 | |
---|
3108 | /* c = 's' (send) or 'r' (receive) */ |
---|
3109 | |
---|
3110 | VOID |
---|
3111 | #ifdef CK_ANSIC |
---|
3112 | logpkt(char c,int n, CHAR *s, int len) |
---|
3113 | #else |
---|
3114 | logpkt(c,n,s,len) char c; int n; CHAR *s; int len; |
---|
3115 | #endif /* CK_ANSIC */ |
---|
3116 | /* logpkt */ { |
---|
3117 | char plog[20]; |
---|
3118 | if (!s) s = (CHAR *)""; |
---|
3119 | if (pktlog) if (chkfn(ZPFILE) > 0) { |
---|
3120 | if (n < 0) /* Construct entry header */ |
---|
3121 | sprintf(plog,"%c-xx-%02d-",c,(gtimer()%60)); /* safe */ |
---|
3122 | else |
---|
3123 | sprintf(plog,"%c-%02d-%02d-",c,n,(gtimer()%60)); /* safe */ |
---|
3124 | if (zsoutx(ZPFILE,plog,(int)strlen(plog)) < 0) { |
---|
3125 | pktlog = 0; |
---|
3126 | return; |
---|
3127 | } else { |
---|
3128 | if (len == 0) |
---|
3129 | len = strlen((char *)s); |
---|
3130 | if (len > 0) { |
---|
3131 | char * p; /* Make SOP printable */ |
---|
3132 | int x; /* so we can look at logs without */ |
---|
3133 | p = dbchr(*s); /* triggering autodownload. */ |
---|
3134 | x = strlen(dbchr(*s)); |
---|
3135 | if (*s < 32 || (*s > 127 && *s < 160)) { |
---|
3136 | if (zsoutx(ZPFILE,p,x) < 0) { |
---|
3137 | pktlog = 0; |
---|
3138 | return; |
---|
3139 | } else { |
---|
3140 | len--; |
---|
3141 | s++; |
---|
3142 | } |
---|
3143 | } |
---|
3144 | } |
---|
3145 | if (zsoutx(ZPFILE,(char *)s,len) < 0) { |
---|
3146 | pktlog = 0; |
---|
3147 | return; |
---|
3148 | } else if (zsoutx(ZPFILE, |
---|
3149 | #ifdef UNIX |
---|
3150 | "\n", 1 |
---|
3151 | #else |
---|
3152 | #ifdef datageneral |
---|
3153 | "\n", 1 |
---|
3154 | #else |
---|
3155 | #ifdef OSK |
---|
3156 | "\r", 1 |
---|
3157 | #else |
---|
3158 | #ifdef MAC |
---|
3159 | "\r", 1 |
---|
3160 | #else |
---|
3161 | "\015\012", 2 |
---|
3162 | #endif /* MAC */ |
---|
3163 | #endif /* OSK */ |
---|
3164 | #endif /* datageneral */ |
---|
3165 | #endif /* UNIX */ |
---|
3166 | ) < 0) { |
---|
3167 | pktlog = 0; |
---|
3168 | } |
---|
3169 | } |
---|
3170 | } |
---|
3171 | } |
---|
3172 | |
---|
3173 | /* T S T A T S -- Record statistics in transaction log */ |
---|
3174 | |
---|
3175 | VOID |
---|
3176 | tstats() { |
---|
3177 | char *tp = NULL; |
---|
3178 | #ifdef GFTIMER |
---|
3179 | CKFLOAT xx; /* Elapsed time divisor */ |
---|
3180 | #endif /* GFTIMER */ |
---|
3181 | |
---|
3182 | debug(F101,"tstats xfsecs","",xfsecs); |
---|
3183 | debug(F101,"tstats filcnt","",filcnt); |
---|
3184 | if (filcnt == 1) { /* Get timing for statistics */ |
---|
3185 | tsecs = xfsecs; /* Single file, we already have it */ |
---|
3186 | #ifdef GFTIMER |
---|
3187 | debug(F101,"tstats fpxfsecs","",(int)fpxfsecs); |
---|
3188 | fptsecs = fpxfsecs; |
---|
3189 | #endif /* GFTIMER */ |
---|
3190 | } else { /* Multiple files */ |
---|
3191 | tsecs = gtimer(); /* Get current time */ |
---|
3192 | #ifdef GFTIMER |
---|
3193 | fptsecs = gftimer(); |
---|
3194 | #endif /* GFTIMER */ |
---|
3195 | } |
---|
3196 | #ifdef GFTIMER |
---|
3197 | if (fptsecs <= GFMINTIME) /* Calculate CPS */ |
---|
3198 | fptsecs = (CKFLOAT) GFMINTIME; |
---|
3199 | debug(F101,"tstats fptsecs","",(int)fptsecs); |
---|
3200 | xx = (CKFLOAT) tfc / fptsecs; |
---|
3201 | if (sizeof(long) <= 4) { /* doesn't account for 16-bit longs */ |
---|
3202 | if (xx > 2147483647.0) |
---|
3203 | tfcps = 2147483647L; /* 31 bits */ |
---|
3204 | else |
---|
3205 | tfcps = (long) xx; |
---|
3206 | } else |
---|
3207 | tfcps = (long) xx; |
---|
3208 | #else |
---|
3209 | if (tsecs < 2L) |
---|
3210 | tsecs = 1L; |
---|
3211 | debug(F101,"tstats tsecs","",tsecs); |
---|
3212 | tfcps = tfc / tsecs; |
---|
3213 | #endif /* GFTIMER */ |
---|
3214 | |
---|
3215 | ztime(&tp); /* Get time stamp */ |
---|
3216 | tlog(F100,"","",0L); /* Leave a blank line */ |
---|
3217 | tlog(F110,"Transaction complete",tp,0L); /* Record it */ |
---|
3218 | |
---|
3219 | if (filcnt < 1) return; /* If no files, done. */ |
---|
3220 | |
---|
3221 | /* If multiple files, record character totals for all files */ |
---|
3222 | |
---|
3223 | if (filcnt > 1) { |
---|
3224 | tlog(F101," files transferred ","",filcnt - filrej); |
---|
3225 | tlog(F101," total file characters ","",tfc); |
---|
3226 | tlog(F101," communication line in ","",tlci); |
---|
3227 | tlog(F101," communication line out ","",tlco); |
---|
3228 | } |
---|
3229 | |
---|
3230 | /* Record timing info for one or more files */ |
---|
3231 | |
---|
3232 | #ifdef GFTIMER |
---|
3233 | if (filcnt - filrej == 1) { |
---|
3234 | tlog(F101," elapsed time (seconds) ","",(long) fpxfsecs); |
---|
3235 | tlog(F101," effective data rate ","",filcps); |
---|
3236 | } else { |
---|
3237 | tlog(F101," elapsed time (seconds) ","",(long) fptsecs); |
---|
3238 | tlog(F101," effective data rate ","",(long) xx); |
---|
3239 | } |
---|
3240 | #else |
---|
3241 | tlog(F101," elapsed time (seconds) ","",(long) tsecs); |
---|
3242 | if (tsecs > 0) { |
---|
3243 | long lx; |
---|
3244 | lx = (tfc * 10L) / (long) tsecs; |
---|
3245 | tlog(F101," effective data rate ","",lx/10L); |
---|
3246 | } |
---|
3247 | #endif /* GFTIMER */ |
---|
3248 | tlog(F100,"","",0L); /* Leave a blank line */ |
---|
3249 | } |
---|
3250 | |
---|
3251 | /* F S T A T S -- Record file statistics in transaction log */ |
---|
3252 | |
---|
3253 | VOID |
---|
3254 | fcps() { |
---|
3255 | #ifdef GFTIMER |
---|
3256 | double xx; |
---|
3257 | fpxfsecs = gftimer() - fpfsecs; |
---|
3258 | if (fpxfsecs <= GFMINTIME) |
---|
3259 | fpxfsecs = (CKFLOAT) GFMINTIME; |
---|
3260 | xx = (CKFLOAT) ffc / fpxfsecs; |
---|
3261 | if (sizeof(long) <= 4) { |
---|
3262 | if (xx > 2147483647.0) |
---|
3263 | tfcps = 2147483647L; /* 31 bits */ |
---|
3264 | else |
---|
3265 | filcps = (long) xx; |
---|
3266 | } else |
---|
3267 | filcps = (long) xx; |
---|
3268 | if (sizeof(int) >= 4) |
---|
3269 | xfsecs = (int) fpxfsecs; |
---|
3270 | else if (fpxfsecs < 32768.0) |
---|
3271 | xfsecs = (int) fpxfsecs; |
---|
3272 | else |
---|
3273 | xfsecs = 32767; |
---|
3274 | #else /* GFTIMER */ |
---|
3275 | xfsecs = gtimer() - fsecs; |
---|
3276 | if (xfsecs < 1L) xfsecs = 1L; |
---|
3277 | filcps = ffc / xfsecs; |
---|
3278 | #endif /* GFTIMER */ |
---|
3279 | } |
---|
3280 | |
---|
3281 | VOID |
---|
3282 | fstats() { |
---|
3283 | tfc += ffc; |
---|
3284 | #ifdef DEBUG |
---|
3285 | if (deblog) { |
---|
3286 | debug(F101,"fstats tfc","",tfc); |
---|
3287 | debug(F101,"fstats what","",what); |
---|
3288 | debug(F110,"fstats epktmsg",epktmsg,0); |
---|
3289 | } |
---|
3290 | #endif /* DEBUG */ |
---|
3291 | #ifdef TLOG |
---|
3292 | if (!discard && !cxseen && !czseen && what != W_NOTHING && !*epktmsg) |
---|
3293 | tlog(F101," complete, size","",ffc); |
---|
3294 | #endif /* TLOG */ |
---|
3295 | } |
---|
3296 | |
---|
3297 | #endif /* NOXFER */ |
---|