|
|
1.1 root 1: /* C K C F N 2 -- System-independent Kermit protocol support functions... */
2:
3: /* ...Part 2 (continued from ckcfns.c) */
4: /*
5: Author: Frank da Cruz (SY.FDC@CU20B),
6: Columbia University Center for Computing Activities, January 1985.
7: Copyright (C) 1985, Trustees of Columbia University in the City of New York.
8: Permission is granted to any individual or institution to use, copy, or
9: redistribute this software so long as it is not sold for profit, provided this
10: copyright notice is retained.
11: */
12: /*
13: Note -- if you change this file, please amend the version number and date at
14: the top of ckcfns.c accordingly.
15: */
16:
17: #include "ckcker.h"
18: #include "ckcdeb.h"
19:
20: extern int spsiz, rpsiz, timint, npad, chklen, ebq, ebqflg, rpt, rptq, rptflg,
21: capas;
22: extern int pktnum, prvpkt, sndtyp, bctr, bctu,
23: size, osize, maxsize, spktl, nfils, stdouf, warn, timef;
24: extern int parity, speed, turn, turnch,
25: delay, displa, pktlog, tralog, seslog, xflg, mypadn;
26: extern long filcnt, ffc, flci, flco, tlci, tlco, tfc, fsize;
27: extern int deblog, hcflg, binary, fncnv, local, server, cxseen, czseen;
28: extern CHAR padch, mypadc, eol, seol, ctlq, myctlq, sstate, *hlptxt;
29: extern CHAR filnam[], sndpkt[], recpkt[], data[], srvcmd[], *srvptr, stchr,
30: mystch;
31: extern char *cmarg, *cmarg2, **cmlist;
32: char *strcpy();
33: CHAR dopar();
34:
35: /* I N P U T -- Attempt to read packet number 'pktnum'. */
36:
37: /*
38: This is the function that feeds input to Kermit's finite state machine.
39:
40: If a special start state is in effect, that state is returned as if it were
41: the type of an incoming packet. Otherwise:
42:
43: . If the desired packet arrives within MAXTRY tries, return its type,
44: with its data stored in the global 'data' array.
45:
46: . If the previous packet arrives again, resend the last packet and wait for
47: another to come in.
48:
49: . If the desired packet does not arrive within MAXTRY tries, return indicating
50: that an error packet should be sent.
51: */
52:
53: input() {
54: int len, num, type, numtry;
55:
56: if (sstate != 0) { /* If a start state is in effect, */
57: type = sstate; /* return it like a packet type, */
58: sstate = 0; /* and then nullify it. */
59: *data = '\0';
60: return(type);
61: } else type = rpack(&len,&num,data); /* Else, try to read a packet. */
62:
63: /* If it's the same packet we just sent, it's an echo. Read another. */
64:
65: if (type == sndtyp) type = rpack(&len,&num,data);
66:
67: chkint(); /* Check for console interrupts. */
68: /*
69: If previous packet again, a timeout pseudopacket, or a bad packet, try again.
70: */
71: for (numtry = 0;
72: (num == prvpkt || type == 'T' || type == 'Q' || type == 'N');
73: numtry++) {
74: if (numtry > MAXTRY) { /* If too many tries, give up */
75: strcpy(data,"Timed out."); /* and send a timeout error packet. */
76: return('E');
77: }
78: resend(); /* Else, send last packet again, */
79: if (sstate != 0) { /* If an interrupt routine has set */
80: type = sstate; /* sstate behind our back, return */
81: sstate = 0; /* that. */
82: *data = '\0';
83: return(type);
84: } else type = rpack(&len,&num,data); /* Else, try to read a packet. */
85: chkint(); /* Look again for interruptions. */
86: if (type == sndtyp) type = rpack(&len,&num,data);
87: }
88: ttflui(); /* Got what we want, clear input buffer. */
89: return(type); /* Success, return packet type. */
90: }
91:
92: /* S P A C K -- Construct and send a packet */
93:
94: spack(type,num,len,dat) char type, *dat; int num, len; {
95: int i,j;
96:
97: j = dopar(padch);
98: for (i = 0; i < npad; sndpkt[i++] = j) /* Do any requested padding */
99: ;
100: sndpkt[i++] = dopar(mystch); /* Start packet with the start char */
101: sndpkt[i++] = dopar(tochar(len+bctu+2)); /* Put in the length */
102: sndpkt[i++] = dopar(tochar(num)); /* The packet number */
103: sndpkt[i++] = dopar(sndtyp = type); /* Packet type */
104:
105: for (j = len; j > 0; j-- ) sndpkt[i++] = dopar(*dat++); /* Data */
106:
107: sndpkt[i] = '\0'; /* Mark end for block check */
108: switch(bctu) {
109: case 1: /* Type 1 - 6 bit checksum */
110: sndpkt[i++] = dopar(tochar(chk1(sndpkt+1)));
111: break;
112: case 2: /* Type 2 - 12 bit checksum*/
113: j = chk2(sndpkt+1);
114: sndpkt[i++] = dopar(tochar((j & 07700) >> 6));
115: sndpkt[i++] = dopar(tochar(j & 077));
116: break;
117: case 3: /* Type 3 - 16 bit CRC-CCITT */
118: j = chk3(sndpkt+1);
119: sndpkt[i++] = dopar(tochar(( (unsigned)(j & 0170000)) >> 12));
120: sndpkt[i++] = dopar(tochar((j & 07700) >> 6));
121: sndpkt[i++] = dopar(tochar(j & 077));
122: break;
123: }
124: for (j = npad; j > 0; j-- ) sndpkt[i++] = dopar(padch); /* Padding */
125:
126: sndpkt[i++] = dopar(seol); /* EOL character */
127: sndpkt[i] = '\0'; /* End of the packet */
128: ttol(sndpkt,spktl=i); /* Send the packet just built */
129: flco += spktl; /* Count the characters */
130: tlco += spktl;
131: if (pktlog) zsoutl(ZPFILE,sndpkt); /* If logging packets, log it */
132: screen(SCR_PT,type,(long)num,sndpkt); /* Update screen */
133: }
134:
135: /* D O P A R -- Add an appropriate parity bit to a character */
136:
137: CHAR
138: dopar(ch) char ch; {
139: int a, b;
140: if (!parity) return(ch); else ch &= 0177;
141: switch (parity) {
142: case 'm': return(ch | 128); /* Mark */
143: case 's': return(ch & 127); /* Space */
144: case 'o': /* Odd (fall thru) */
145: case 'e': /* Even */
146: a = (ch & 15) ^ ((ch >> 4) & 15);
147: a = (a & 3) ^ ((a >> 2) & 3);
148: a = (a & 1) ^ ((a >> 1) & 1);
149: if (parity == 'o') a = 1 - a; /* Switch sense for odd */
150: return(ch | (a << 7));
151: default: return(ch);
152: }
153: }
154:
155: /* C H K 1 -- Compute a type-1 Kermit 6-bit checksum. */
156:
157: chk1(pkt) char *pkt; {
158: int chk;
159: chk = chk2(pkt);
160: return((((chk & 0300) >> 6) + chk) & 077);
161: }
162:
163:
164: /* C H K 2 -- Compute the numeric sum of all the bytes in the packet. */
165:
166: chk2(pkt) char *pkt; {
167: unsigned int chk;
168: int p;
169: for (chk = 0; *pkt != '\0'; *pkt++) {
170: p = (parity) ? *pkt & 0177 : *pkt;
171: chk += p;
172: }
173: return(chk);
174: }
175:
176:
177: /* C H K 3 -- Compute a type-3 Kermit block check. */
178: /*
179: Calculate the 16-bit CRC of a null-terminated string using a byte-oriented
180: tableless algorithm invented by Andy Lowry (Columbia University). The
181: magic number 010201 is derived from the CRC-CCITT polynomial x^16+x^12+x^5+1.
182: Note - this function could be adapted for strings containing imbedded 0's
183: by including a length argument.
184: */
185: chk3(s) char *s; {
186: unsigned int c, q;
187: LONG crc = 0;
188:
189: while ((c = *s++) != '\0') {
190: if (parity) c &= 0177;
191: q = (crc ^ c) & 017; /* Low-order nibble */
192: crc = (crc >> 4) ^ (q * 010201);
193: q = (crc ^ (c >> 4)) & 017; /* High order nibble */
194: crc = (crc >> 4) ^ (q * 010201);
195: }
196: return(crc);
197: }
198:
199: /* Functions for sending various kinds of packets */
200:
201: ack() { /* Send an ordinary acknowledgment. */
202: spack('Y',pktnum,0,""); /* No data. */
203: nxtpkt(&pktnum); /* Increment the packet number. */
204: } /* Note, only call this once! */
205:
206: ack1(s) char *s; { /* Send an ACK with data. */
207: spack('Y',pktnum,strlen(s),s); /* Send the packet. */
208: nxtpkt(&pktnum); /* Increment the packet number. */
209: } /* Only call this once! */
210:
211: nack() { /* Negative acknowledgment. */
212: spack('N',pktnum,0,""); /* NAK's never have data. */
213: }
214:
215: resend() { /* Send the old packet again. */
216: int w;
217:
218: for (w = 0; w < timint - 2; w++) { /* Be extra sure no stuff is */
219: ttflui(); /* still coming in. */
220: sleep(1);
221: if (!ttchk() ) ttinc(1); /* be extra sure no stuff in SIII/V */
222: if (!ttchk() ) break;
223: }
224: if (*sndpkt) ttol(sndpkt,spktl); /* Resend if buffer not empty */
225: screen(SCR_PT,'%',(long)pktnum,sndpkt); /* Display that resend occurred */
226: if (pktlog && *sndpkt) zsoutl(ZPFILE,sndpkt); /* Log packet if desired */
227: }
228:
229: errpkt(reason) char *reason; { /* Send an error packet. */
230: encstr(reason);
231: spack('E',pktnum,size,data);
232: screen(SCR_TC,0,0l,"");
233: }
234:
235: scmd(t,dat) char t, *dat; { /* Send a packet of the given type */
236: encstr(dat); /* Encode the command string */
237: spack(t,pktnum,size,data);
238: }
239:
240: srinit() { /* Send R (GET) packet */
241: encstr(cmarg); /* Encode the filename. */
242: spack('R',pktnum,size,data); /* Send the packet. */
243: }
244:
245: nxtpkt(num) int *num; {
246: prvpkt = *num; /* Save previous */
247: *num = (*num + 1) % 64; /* Increment packet number mod 64 */
248: }
249:
250: sigint() { /* Terminal interrupt handler */
251: errpkt("User typed ^C");
252: doexit(GOOD_EXIT); /* Exit program */
253: }
254:
255: /* R P A C K -- Read a Packet */
256:
257: rpack(l,n,dat) int *l, *n; char *dat; {
258: int i, j, x, done, pstart, pbl, cccount, tries, gotsoh;
259: CHAR chk[4], xchk[4], t, type;
260:
261: /* Try 3 times to get a line that has a start-of-packet char in it. */
262: /* This allows skipping of blank lines that some hosts might send. */
263:
264: for (gotsoh = tries = 0; (tries < 3) && (gotsoh == 0); tries++) {
265: j = inlin(); /* Read a line */
266: if (j < 0) {
267: debug(F101,"rpack: inlin fails","",j);
268: screen(SCR_PT,'T',(long)pktnum,"");
269: return('T');
270: }
271: debug(F111,"rpack: inlin ok, recpkt",recpkt,j);
272: for (i = 0; ((t = recpkt[i]) != stchr) && (i < j); i++)
273: ; /* Look for start of packet char */
274: gotsoh = (t == stchr);
275: }
276: if (gotsoh) i++; else return('Q'); /* No SOH in 3 tries, fail. */
277:
278: /* Got something that starts out like a packet, now "parse" it. */
279:
280: debug(F101,"entering rpack with i","",i);
281: done = 0;
282: while (!done) {
283: debug(F101,"rpack starting at i","",i);
284: pstart = i; /* remember where packet started */
285:
286: /* length */
287:
288: if ((t = recpkt[i++]) == stchr) continue; /* Resynch if SOH */
289:
290: if (t == 3) cccount++; /* Count any control-C's */
291:
292: if (t == eol) return('Q');
293: *l = unchar(t); /* Packet length */
294: debug(F101," pkt len","",*l);
295:
296: /* sequence number */
297:
298: if ((t = recpkt[i++]) == stchr) continue;
299: if (cccount && (t == 3)) { conoll("^C^C exit..."); doexit(0); }
300: if (t == eol) return('Q');
301: *n = unchar(t);
302: debug(F101,"rpack: n","",*n);
303:
304: /* cont'd... */
305:
306: /* ...rpack(), cont'd */
307:
308:
309: /* type */
310:
311: if ((type = recpkt[i++]) == stchr) continue;
312: if (type == eol) return('Q');
313: debug(F101,"rpack: type","",type);
314:
315: if ((type == 'S') || (type == 'I')) pbl = 1; /* Heuristics for */
316: else if (type == 'N') pbl = *l - 2; /* syncing block check type */
317: else pbl = bctu;
318:
319: *l -= (pbl + 2); /* Now compute data length */
320: debug(F101,"rpack: bctu","",bctu);
321: debug(F101," pbl","",pbl);
322: debug(F101," data length","",*l);
323:
324: /* data */
325:
326: dat[0] = '\0'; /* Return null string if no data */
327: for (j=0; j<*l; i++,j++)
328: if ((dat[j] = recpkt[i]) == stchr) continue;
329: else if (dat[j] == eol) return('Q');
330: dat[j] = '\0';
331:
332: /* get the block check */
333:
334: debug(F110," packet chk",recpkt+i,0);
335: for (j = 0; j < pbl; j++) {
336: chk[j] = recpkt[i];
337: debug(F101," chk[j]","",chk[j]);
338: if (chk[j] == stchr) break;
339: if (chk[j] == eol) return('Q');
340: recpkt[i++] = '\0';
341: }
342: chk[j] = 0;
343: debug(F111," chk array, j",chk,j);
344: if (j != pbl) continue; /* Block check right length? */
345: done = 1; /* Yes, done. */
346: }
347:
348: /* cont'd... */
349:
350: /* ...rpack(), cont'd */
351:
352:
353: /* Got packet, now check the block check */
354:
355: switch (pbl) {
356: case 1:
357: xchk[0] = tochar(chk1(&recpkt[pstart]));
358: if (chk[0] != xchk[0]) {
359: if (deblog) {
360: debug(F000,"rpack: chk","",chk[0]);
361: debug(F000," should be ","",xchk[0]);
362: }
363: screen(SCR_PT,'Q',(long)n,recpkt);
364: return('Q');
365: }
366: break;
367: case 2:
368: x = chk2(&recpkt[pstart]);
369: xchk[0] = tochar((x & 07700) >> 6);
370: xchk[1] = tochar(x & 077);
371: if (deblog) {
372: debug(F000," xchk[0]","=",xchk[0]);
373: debug(F000," xchk[1]","=",xchk[1]);
374: }
375: if ((xchk[0] != chk[0]) || (xchk[1] != chk[1])) {
376: debug(F100," bct2's don't compare","",0);
377: screen(SCR_PT,'Q',(long)n,recpkt);
378: return('Q');
379: }
380: break;
381: case 3:
382: x = chk3(&recpkt[pstart]);
383: xchk[0] = tochar(( (unsigned)(x & 0170000)) >> 12);
384: xchk[1] = tochar((x & 07700) >> 6);
385: xchk[2] = tochar(x & 077);
386: if (deblog) {
387: debug(F000," xchk[0]","=",xchk[0]);
388: debug(F000," xchk[1]","=",xchk[1]);
389: debug(F000," xchk[2]","=",xchk[2]);
390: }
391: if ((xchk[0] != chk[0]) ||
392: (xchk[1] != chk[1]) ||
393: (xchk[2] != chk[2])) {
394: debug(F100," bct3's don't compare","",0);
395: screen(SCR_PT,'Q',(long)n,recpkt);
396: return('Q');
397: }
398: break;
399: }
400:
401: /* Good packet, return its type */
402:
403: screen(SCR_PT,type,(long)(*n),recpkt); /* Update screen */
404: return(type);
405: }
406:
407: /* I N C H R -- Input character from communication line, with timeout */
408:
409: inchr(timo) int timo; {
410: int c;
411: c = ttinc(timo);
412: debug(F101,"inchr ttinc","",c);
413: if (c < 0) return(c); /* Get a character */
414: if (parity) c = c & 0177; /* If parity on, discard parity bit. */
415: debug(F101," after parity","",c);
416: return(c);
417: }
418:
419:
420: /* I N L I N -- Input a line (up to break char) from communication line */
421:
422: /* Returns number of chars input on success, -1 on failure. */
423: /* Number of chars guaranteed to be within RBUFL. */
424:
425: inlin() {
426: int i, j, k, maxt;
427: CHAR e;
428:
429: maxt = (speed >= 110) ? (MAXTRY * 9600 / speed) : MAXTRY;
430: debug(F101,"inlin: speed","",speed);
431: debug(F101," maxt","",maxt);
432: e = (turn) ? turnch : eol;
433: i = j = k = 0;
434: if (parity) {
435: while ((j != e) && (i < RBUFL) && (k < maxt)) {
436: j = inchr(1); /* Get char, 1 second timeout */
437: debug(F101,"inlin inchr","",j);
438: if (j < 0) k++; /* Timed out, count. */
439: else {
440: if (j) recpkt[i++] = j; /* Got one, save it, */
441: k = 0; /* and reset timeout counter. */
442: }
443: }
444: } else {
445: i = ttinl(recpkt,RBUFL,timint,e); /* Get them all at once */
446: if (i < 0) k = 1;
447: }
448: recpkt[i+1] = '\0'; /* Terminate near end of packet */
449: debug(F111,"inlin",recpkt,i); /* Debug report... */
450: debug(F101," timeouts","",k);
451: if (i < 1) return(-1); /* No characters, return. */
452: if (pktlog) zsoutl(ZPFILE,recpkt); /* Log any we got, if logging. */
453: if (k > maxt) return(-1); /* If too many tries, give up. */
454: tlci += i; /* All OK, Count the characters. */
455: flci += i;
456: return(i);
457: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.