|
|
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: Modified July 87 to incorporate changes from Jim Noble of
6: Planning Research Corp for Macintosh Megamax C support.
7: */
8: /*
9: Author: Frank da Cruz (SY.FDC@CU20B),
10: Columbia University Center for Computing Activities, January 1985.
11: Copyright (C) 1985, Trustees of Columbia University in the City of New York.
12: Permission is granted to any individual or institution to use, copy, or
13: redistribute this software so long as it is not sold for profit, provided this
14: copyright notice is retained.
15: */
16: /*
17: Note -- if you change this file, please amend the version number and date at
18: the top of ckcfns.c accordingly.
19: */
20:
21: #include "ckcsym.h" /* Conditional compilation (for Macintosh) */
22: #include "ckcker.h"
23: #include "ckcdeb.h"
24:
25: extern int spsiz, rpsiz, timint, npad, ebq, ebqflg, rpt, rptq, rptflg, capas;
26: extern int pktnum, prvpkt, sndtyp, bctr, bctu, rsn, rln, maxtry, size;
27: extern int osize, maxsize, spktl, nfils, stdouf, warn, timef, parity, speed;
28: extern int turn, turnch, delay, displa, pktlog, tralog, seslog, xflg, mypadn;
29: extern int deblog, hcflg, binary, fncnv, local, server, cxseen, czseen;
30: extern long filcnt, ffc, flci, flco, tlci, tlco, tfc, fsize;
31: extern char *cmarg, *cmarg2, **cmlist;
32: extern CHAR padch, mypadc, eol, seol, ctlq, myctlq, sstate, *hlptxt;
33: extern CHAR filnam[], sndpkt[], recpkt[], data[], srvcmd[];
34: extern CHAR *srvptr, stchr, mystch, *rdatap;
35:
36: char *strcpy(); /* Forward declarations */
37: unsigned chk2(); /* of non-int functions */
38: CHAR dopar(); /* ... */
39:
40: static CHAR partab[] = { /* Even parity table for dopar() */
41:
42: '\000', '\201', '\202', '\003', '\204', '\005', '\006', '\207',
43: '\210', '\011', '\012', '\213', '\014', '\215', '\216', '\017',
44: '\220', '\021', '\022', '\223', '\024', '\225', '\226', '\027',
45: '\030', '\231', '\232', '\033', '\234', '\035', '\036', '\237',
46: '\240', '\041', '\042', '\243', '\044', '\245', '\246', '\047',
47: '\050', '\251', '\252', '\053', '\254', '\055', '\056', '\257',
48: '\060', '\261', '\262', '\063', '\264', '\065', '\066', '\267',
49: '\270', '\071', '\072', '\273', '\074', '\275', '\276', '\077',
50: '\300', '\101', '\102', '\303', '\104', '\305', '\306', '\107',
51: '\110', '\311', '\312', '\113', '\314', '\115', '\116', '\317',
52: '\120', '\321', '\322', '\123', '\324', '\125', '\126', '\327',
53: '\330', '\131', '\132', '\333', '\134', '\335', '\336', '\137',
54: '\140', '\341', '\342', '\143', '\344', '\145', '\146', '\347',
55: '\350', '\151', '\152', '\353', '\154', '\355', '\356', '\157',
56: '\360', '\161', '\162', '\363', '\164', '\365', '\366', '\167',
57: '\170', '\371', '\372', '\173', '\374', '\175', '\176', '\377'
58: };
59:
60: /* I N P U T -- Attempt to read packet number 'pktnum'. */
61:
62: /*
63: This is the function that feeds input to Kermit's finite state machine.
64:
65: If a special start state is in effect, that state is returned as if it were
66: the type of an incoming packet. Otherwise:
67:
68: . If the desired packet arrives within MAXTRY tries, return its type,
69: with its data stored in the global 'data' array.
70:
71: . If the previous packet arrives again, resend the last packet and wait for
72: another to come in.
73:
74: . If the desired packet does not arrive within MAXTRY tries, return indicating
75: that an error packet should be sent.
76: */
77:
78: input() {
79: int type, numtry;
80:
81: if (sstate != 0) { /* If a start state is in effect, */
82: type = sstate; /* return it like a packet type, */
83: sstate = 0; /* and then nullify it. */
84: return(type);
85: } else type = rpack(); /* Else, try to read a packet. */
86:
87: debug(F111,"input",rdatap,type);
88:
89: /* If it's the same packet we just sent, it's an echo. Read another. */
90:
91: if (type == sndtyp) type = rpack();
92:
93: chkint(); /* Check for console interrupts. */
94: /*
95: If previous packet again, a timeout pseudopacket, or a bad packet, try again.
96: */
97: for (numtry = 0;
98: (rsn == prvpkt || type == 'T' || type == 'Q' || type == 'N');
99: numtry++) {
100: if (numtry > maxtry) { /* If too many tries, give up */
101: strcpy(data,"Timed out."); /* and send a timeout error packet, */
102: rdatap = data; /* and pretend we read one. */
103: return('E');
104: }
105: if (type == 'E') return('E'); /* Don't even bother about seq no */
106: if ((type == 'N') && (rsn == ((pktnum+1) & 63))) {
107: /* NAK for next packet */
108: return('Y'); /* is ACK for current. */
109: } else {
110: resend(); /* Else, send last packet again, */
111: }
112: if (sstate != 0) { /* If an interrupt routine has set */
113: type = sstate; /* sstate behind our back, return */
114: sstate = 0; /* that. */
115: *data = '\0';
116: return(type);
117: } else type = rpack(); /* Else try to read a packet. */
118: chkint(); /* Look again for interruptions. */
119: if (type == sndtyp) type = rpack();
120: }
121: ttflui(); /* Got what we want, clear input buffer. */
122: return(type); /* Success, return packet type. */
123: }
124:
125:
126: /* S P A C K -- Construct and send a packet */
127:
128: /*
129: spack() sends a packet of the given type, sequence number n, with len
130: data characters pointed to by d, in either a regular or extended-
131: length packet, depending on length. Returns the number of bytes
132: actually sent, or else -1 upon failure. Uses global npad, padch,
133: mystch, bctu. Leaves packet in null-terminated global sndpkt[] array for
134: later retransmission. Updates global sndpktl (send-packet length).
135: */
136:
137: spack(type,n,len,d) char type, *d; int n, len; {
138: int i, j, lp; CHAR *sohp = sndpkt; CHAR pc;
139:
140: spktl = 0;
141: pc = dopar(padch); /* The pad character, if any. */
142: for (i = 0; i < npad; sndpkt[i++] = pc) /* Do any requested padding */
143: sohp++;
144: sndpkt[i++] = dopar(mystch); /* MARK */
145: lp = i++; /* Position of LEN, fill in later */
146: sndpkt[i++] = dopar(tochar(n)); /* SEQ field */
147: sndpkt[i++] = dopar(sndtyp = type); /* TYPE field */
148: j = len + bctu; /* True length */
149: if (j > 95) { /* Long packet? */
150: sndpkt[lp] = dopar(tochar(0)); /* Set LEN to zero */
151: sndpkt[i++] = dopar(tochar(j / 95)); /* High part */
152: sndpkt[i++] = dopar(tochar(j % 95)); /* Low part */
153: sndpkt[i] = '\0'; /* Header checksum */
154: sndpkt[i++] = dopar(tochar(chk1(sndpkt+lp)));
155: } else sndpkt[lp] = dopar(tochar(j+2)); /* Normal LEN */
156:
157: while (len-- > 0) sndpkt[i++] = dopar(*d++); /* Packet data */
158: sndpkt[i] = '\0'; /* Null-terminate */
159:
160: switch (bctu) { /* Block check */
161: case 1: /* 1 = 6-bit chksum */
162: sndpkt[i++] = dopar(tochar(chk1(sndpkt+lp)));
163: break;
164: case 2: /* 2 = 12-bit chksum */
165: j = chk2(sndpkt+lp);
166: sndpkt[i++] = dopar( (unsigned) tochar((j >> 6) & 077));
167: sndpkt[i++] = dopar( (unsigned) tochar(j & 077));
168: break;
169: case 3: /* 3 = 16-bit CRC */
170: j = chk3(sndpkt+lp);
171: sndpkt[i++] = dopar(tochar(( (unsigned)(j & 0170000)) >> 12));
172: sndpkt[i++] = dopar(tochar((j >> 6) & 077));
173: sndpkt[i++] = dopar(tochar(j & 077));
174: break;
175: }
176: sndpkt[i++] = dopar(seol); /* End of line (packet terminator) */
177: sndpkt[i] = '\0'; /* Terminate string */
178: if (ttol(sndpkt,i) < 0) return(-1); /* Send the packet */
179: spktl = i; /* Remember packet length */
180: flco += spktl; /* Count the characters */
181: tlco += spktl;
182: if (pktlog) { /* If logging packets, log it */
183: zsout(ZPFILE,"s-");
184: if (*sndpkt) zsoutl(ZPFILE,sndpkt); else zsoutl(ZPFILE,sohp);
185: }
186: screen(SCR_PT,type,(long)n,sohp); /* Update screen */
187: return(i); /* Return length */
188: }
189:
190: /* D O P A R -- Add an appropriate parity bit to a character */
191:
192: CHAR
193: dopar(ch) CHAR ch; {
194: int a;
195: if (!parity) return(ch & 255); else a = ch & 127;
196: switch (parity) {
197: case 'e': return(partab[a]) & 255; /* Even */
198: case 'm': return(a | 128); /* Mark */
199: case 'o': return(partab[a] ^ 128) & 255; /* Odd */
200: case 's': return(a & 127); /* Space */
201: default: return(a);
202: }
203: }
204:
205: /* C H K 1 -- Compute a type-1 Kermit 6-bit checksum. */
206:
207: chk1(pkt) char *pkt; {
208: unsigned int chk;
209: chk = chk2(pkt);
210: chk = (((chk & 0300) >> 6) + chk) & 077;
211: return(chk);
212: }
213:
214: /* C H K 2 -- Compute the numeric sum of all the bytes in the packet. */
215:
216: unsigned
217: chk2(pkt) CHAR *pkt; {
218: long chk; unsigned int m;
219: m = (parity) ? 0177 : 0377;
220: for (chk = 0; *pkt != '\0'; pkt++)
221: chk += *pkt & m;
222: return(chk & 07777);
223: }
224:
225:
226: /* C H K 3 -- Compute a type-3 Kermit block check. */
227: /*
228: Calculate the 16-bit CRC of a null-terminated string using a byte-oriented
229: tableless algorithm invented by Andy Lowry (Columbia University). The
230: magic number 010201 is derived from the CRC-CCITT polynomial x^16+x^12+x^5+1.
231: Note - this function could be adapted for strings containing imbedded 0's
232: by including a length argument. Another note - Replacing this function by
233: a table lookup version might speed things up.
234: */
235: chk3(s) char *s; {
236: unsigned int c, q;
237: LONG crc = 0;
238:
239: while ((c = *s++) != '\0') {
240: if (parity) c &= 0177; /* Strip any parity */
241: q = (crc ^ c) & 017; /* Low-order nibble */
242: crc = (crc >> 4) ^ (q * 010201);
243: q = (crc ^ (c >> 4)) & 017; /* High order nibble */
244: crc = (crc >> 4) ^ (q * 010201);
245: }
246: return(crc);
247: }
248:
249: /* Functions for sending various kinds of packets */
250:
251: ack() { /* Send an ordinary acknowledgment. */
252: spack('Y',pktnum,0,""); /* No data. */
253: nxtpkt(&pktnum); /* Increment the packet number. */
254: } /* Note, only call this once! */
255:
256: ack1(s) char *s; { /* Send an ACK with data. */
257: spack('Y',pktnum,strlen(s),s); /* Send the packet. */
258: nxtpkt(&pktnum); /* Increment the packet number. */
259: } /* Only call this once! */
260:
261: nack() { /* Negative acknowledgment. */
262: spack('N',pktnum,0,""); /* NAK's never have data. */
263: }
264:
265: resend() { /* Send the old packet again. */
266: if (spktl) /* If buffer has something, */
267: ttol(sndpkt,spktl); /* resend it, */
268: else nack(); /* otherwise send a NAK. */
269:
270: debug(F111,"resend",sndpkt,spktl);
271: screen(SCR_PT,'%',(long)pktnum,"(resend)"); /* Say resend occurred */
272: if (pktlog) {
273: zsout(ZPFILE,"s-");
274: zsoutl(ZPFILE,"(resend)"); /* Log packet if desired */
275: }
276: }
277:
278: errpkt(reason) char *reason; { /* Send an error packet. */
279: encstr(reason);
280: spack('E',pktnum,size,data);
281: clsif(); clsof(1);
282: screen(SCR_TC,0,0l,"");
283: }
284:
285: scmd(t,dat) char t, *dat; { /* Send a packet of the given type */
286: encstr(dat); /* Encode the command string */
287: spack(t,pktnum,size,data);
288: }
289:
290: srinit() { /* Send R (GET) packet */
291: encstr(cmarg); /* Encode the filename. */
292: spack('R',pktnum,size,data); /* Send the packet. */
293: }
294:
295: nxtpkt(num) int *num; {
296: prvpkt = *num; /* Save previous */
297: *num = (*num + 1) % 64; /* Increment packet number mod 64 */
298: }
299:
300: sigint() { /* Terminal interrupt handler */
301: errpkt("User typed ^C");
302: doexit(GOOD_EXIT); /* Exit program */
303: }
304:
305: /* R P A C K -- Read a Packet */
306:
307: /*
308: rpack reads a packet and returns the packet type, or else Q if the
309: packet was invalid, or T if a timeout occurred. Upon successful return, sets
310: the values of global rsn (received sequence number), rln (received
311: data length), and rdatap (pointer to null-terminated data field).
312: */
313: rpack() {
314: int i, j, x, try, type, lp; /* Local variables */
315: CHAR pbc[4]; /* Packet block check */
316: CHAR *sohp = recpkt; /* Pointer to SOH */
317: CHAR e; /* Packet end character */
318:
319: rsn = rln = -1; /* In case of failure. */
320: *recpkt = '\0'; /* Clear receive buffer. */
321:
322: e = (turn) ? turnch : eol; /* Use any handshake char for eol */
323:
324: /* Try several times to get a "line". This allows for hosts that echo our */
325: /* normal CR packet terminator as CRLF. Don't diagnose CRLF as an */
326: /* invalid packet. */
327:
328: #define TTITRY 3
329:
330: for (try = 0; try < TTITRY; try++) { /* Try x times to get a "line". */
331: j = ttinl(recpkt,MAXRP,timint,e);
332: if (j < 0) {
333: if (j < -1) doexit(BAD_EXIT); /* Bail out if ^C^C typed. */
334: debug(F101,"rpack: ttinl fails","",j);
335: screen(SCR_PT,'T',(long)pktnum,"");
336: return('T'); /* Otherwise, call it a timeout. */
337: }
338: tlci += j; /* All OK, Count the characters. */
339: flci += j;
340:
341: for (i = 0; (recpkt[i] != stchr) && (i < j); i++)
342: sohp++; /* Find mark */
343: if (i++ < j) break; /* Found it. */
344: }
345: if (try >= TTITRY) return('Q'); /* Diagnose bad packet. */
346:
347: debug(F111,"ttinl",sohp,j); /* Log packet if requested. */
348: if (pktlog) {
349: zsout(ZPFILE,"r-");
350: zsoutl(ZPFILE,sohp);
351: }
352: lp = i; /* Remember LEN position. */
353: if ((j = xunchar(recpkt[i++])) == 0) {
354: if ((j = lp+5) > MAXRP) return('Q'); /* Long packet */
355: x = recpkt[j]; /* Header checksum. */
356: recpkt[j] = '\0'; /* Calculate & compare. */
357: if (xunchar(x) != chk1(recpkt+lp)) return('Q');
358: recpkt[j] = x; /* Checksum ok. */
359: rln = xunchar(recpkt[j-2]) * 95 + xunchar(recpkt[j-1]) - bctu;
360: j = 3; /* Data offset. */
361: } else if (j < 3) {
362: debug(F101,"rpack packet length less than 3","",j);
363: return('Q');
364: } else {
365: rln = j - bctu - 2; /* Regular packet */
366: j = 0; /* No extended header */
367: }
368: rsn = xunchar(recpkt[i++]); /* Sequence number */
369: type = recpkt[i++]; /* Packet type */
370: i += j; /* Where data begins */
371: rdatap = recpkt+i; /* The data itself */
372: if ((j = rln + i) > MAXRP ) {
373: debug(F101,"packet sticks out too far","",j);
374: return('Q'); /* Find block check */
375: }
376: /** debug(F101,"block check at","",j); **/
377: for (x = 0; x < bctu; x++) /* Copy it */
378: pbc[x] = recpkt[j+x];
379:
380: pbc[x] = '\0';
381: /** debug(F110,"block check",pbc,bctu); **/
382: recpkt[j] = '\0'; /* Null-terminate data */
383:
384: switch (bctu) { /* Check the block check */
385: case 1:
386: if (xunchar(*pbc) != chk1(recpkt+lp)) {
387: debug(F110,"checked chars",recpkt+lp,0);
388: debug(F101,"block check","",xunchar(*pbc));
389: debug(F101,"should be","",chk1(recpkt+lp));
390: return('Q');
391: }
392: break;
393: case 2:
394: x = xunchar(*pbc) << 6 | xunchar(pbc[1]);
395: if (x != chk2(recpkt+lp)) {
396: debug(F110,"checked chars",recpkt+lp,0);
397: debug(F101,"block check","", x);
398: debug(F101,"should be","", chk2(recpkt+lp));
399: return('Q');
400: }
401: break;
402: case 3:
403: x = xunchar(*pbc) << 12 | xunchar(pbc[1]) << 6 | xunchar(pbc[2]);
404: if (x != chk3(recpkt+lp)) {
405: debug(F110,"checked chars",recpkt+lp,0);
406: debug(F101,"block check","",xunchar(*pbc));
407: debug(F101,"should be","",chk1(recpkt+lp));
408: return('Q');
409: }
410: break;
411: default: return('Q');
412: }
413: screen(SCR_PT,type,(long)rsn,sohp); /* Update screen */
414: return(type); /* Return packet type */
415: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.