📄 ckcfn2.c
字号:
if (wslots > 1) { /* Packet at winlo already ACK'd? */ if (sacktbl[winlo]) { /* If so, */ sacktbl[winlo] = 0; /* Turn off the ACK'd flag */ winlo = (winlo + 1) % 64; /* Rotate the window */ type = 'Y'; /* And return ACK */ debug(F101, "input send returning pre-stashed ACK","", winlo-1); break; } } type = rpack(); /* Try to read an acknowledgement */ debug(F111,"input send",(char *) rdatap,(int) type); while (type == 'e') { /* Handle echoes */ debug(F000,"echo discarded","",type); type = rpack(); } if (type == -2) return('q'); if (type == -1) { errpkt((CHAR *)"Internal error number 18"); debug(F101," wslots","",wslots); debug(F101," winlo","",winlo); debug(F101," pktnum","",pktnum); dumprbuf(); strcpy((char *)recpkt,"Can't allocate receive buffer"); type = 'E'; break; } dumprbuf(); /* debugging */ if (chkint() < 0) { /* Check for console interrupts. */ errpkt((CHAR *)"User cancelled."); strcpy((char *)recpkt,"User cancelled."); return(type = 'E'); } /* got a packet */ if (type == 'E') { debug(F101,"input send got E, nakstate","",nakstate); break; /* Error packet */ } if (type == 'Q') { /* Crunched packet */ crunched++; /* For statistics */ numerrs++; /* For packet resizing */ x = resend(winlo); /* Resend window-low */ if (x < 0) { type = 'E'; errpkt(recpkt); break; } continue; } if (type == 'T') { /* Timeout waiting for ACKs. */ timeouts++; /* Count it */ numerrs++; /* Count an error too */ debug(F101,"input send state timeout, winlo","",winlo); /* Retransmit the oldest un-ACK'd packet. */ debug(F101,"input send resending winlo","",winlo); if (resend(winlo) < 0) { /* Check retries */ debug(F101,"input send too many resends","",maxtry); errpkt(recpkt); return(type = 'E'); } continue; } /* Got an actual normal packet */ y = chkwin(rsn,winlo,wslots); /* Is it in the window? */ debug(F101,"input send rsn","",rsn); debug(F101,"input send winlo","",winlo); debug(F101,"input send chkwin","",y); if (type == 'Y') { /* Got an ACK */ if (y == 0) { /* In current window */ x = sseqtbl[rsn]; /* Mark the packet as ACK'd */ if (x > -1) s_pkt[x].pk_flg++; /* (old way) */ sacktbl[rsn]++; /* (new way) *//* NOTE: The following statement frees the buffer of the ACK we just got. But the upper layers still need the data, like if it's the ACK to an I, S, F, D, Z, or just about any kind of packet. So for now, freerbuf() deallocates the buffer, but does not erase the data or destroy the pointer to it. There's no other single place where these receive buffers can be correctly freed (?) ...*/ freerpkt(rsn); /* Free the ACK's buffer */ freesbuf(rsn); /* *** Free the sent packet's buffer */ if (rsn == winlo) { /* Got the one we want */ sacktbl[winlo] = 0; winlo = (winlo + 1) % 64; debug(F101,"input send rotated send window","",winlo); break; /* Return the ACK */ } else { debug(F101,"input send mark pkt","",rsn); continue; /* Otherwise go read another packet */ } } else { /* ACK not in window, ignore */ debug(F101,"input send ACK out of window","",rsn); freerpkt(rsn); continue; } } if (type == 'N') { /* NAK */ numerrs++; /* Count an error */ debug(F101,"input send NAK","",rsn); freerpkt(rsn); /* Free buffer where NAK lies. */ if (y == 0) { /* In current window */ debug(F100," in window","",0); k = sseqtbl[rsn]; /* Get pointer to NAK'd packet. */ x = 0; if (k < 0 || (k > -1 && s_pkt[k].pk_typ == ' ')) { x = resend(winlo); /* Packet we haven't sent yet. */ } else { x = resend(rsn); /* Resend requested packet. */ } if (x < 0) { /* Resend error is fatal. */ type = 'E'; errpkt(recpkt); break; } else continue; /* Resend ok, go read another packet */ } else if ((rsn == (pktnum + 1) % 64)) { /* NAK for next pkt */ if (wslots > 1) { debug( F101,"NAK for next packet, windowing","",rsn); x = resend(winlo); /* Resend window-low */ if (x < 0) { type = 'E'; errpkt(recpkt); break; } continue; /* Go back and read another pkt */ } debug(F101,"NAK for next packet, no windowing","",rsn); x = (rsn == 0) ? 63 : rsn - 1; if (x == 0 && (sndtyp == 'S' || sndtyp == 'I')) { resend(0); /* ACK for S or I packet missing */ continue; /* so resend it. */ } /* Else, treat NAK(n+1) as ACK(n) */ if ((x = sseqtbl[x]) > -1) { sacktbl[x]++; /* (new way) */ s_pkt[x].pk_flg++; /* (old way) */ } type = 'Y'; /* Treat it as ACK for last pkt */ break; } else if (y > 0) { /* NAK for pkt we can't resend */ debug(F101," NAK out of window","",rsn); /* bad... */ type = 'E'; errpkt((CHAR *)"NAK out of window"); strcpy((char *)recpkt,"NAK out of window."); break; } else continue; /* Ignore other NAKs */ } /* End of file-sender NAK handler */ if (rsn == winlo) { /* Not ACK, NAK, timeout, etc. */ debug(F000,"input send unexpected type","",type); break; } } /* End of file-sender section */ } /* End of input() loop */ if (wslots == 1) { debug(F100,"input about to flush","",0); ttflui(); /* Got what we want, clear input buffer. */ } if (!nakstate) /* When sending */ rcalcpsz(); /* recalculate size every packet */ debug(F000,"input returning type","",type); return(type); /* Success, return packet type. */}/* D O P A R -- Add an appropriate parity bit to a character *//* (PWP) this is still used in the Mac terminal emulator, so we have to keep it*/CHAR#ifdef CK_ANSICdopar(register CHAR ch)#elsedopar(ch) register CHAR ch;#endif /* CK_ANSIC */ { register unsigned int a; if (!parity) return((CHAR) (ch & 255)); else a = ch & 127; switch (parity) { case 'e': return(partab[a]); /* Even */ case 'm': return((CHAR) (a | 128)); /* Mark */ case 'o': return((CHAR) (partab[a] ^ 128)); /* Odd */ case 's': return((CHAR) a); /* Space */ default: return((CHAR) a); /* Something illegal */ }}#ifdef PARSENSE/* P A R C H K -- Check if Kermit packet has parity *//* Call with s = pointer to packet, start = packet start character, n = length. Returns 0 if packet has no parity, -1 on error, or, if packet has parity: 'e' for even, 'o' for odd, 'm' for mark. Space parity cannot be sensed. So a return value of 0 really means either space or none. Returns -2 if parity has already been checked during this protocol operation.*/int#ifdef CK_ANSICparchk(CHAR *s, CHAR start, int n)#elseparchk(s,start,n) CHAR *s, start; int n;#endif /* CK_ANSIC *//* parchk */ { CHAR s0, s1, s2, s3; debug(F101,"parchk n","",n); debug(F101,"parchk start","",start); s0 = s[0] & 0x7f; /* Mark field (usually Ctrl-A) */ if (s0 != start || n < 5) return(-1); /* Not a valid packet *//* Look at packet control fields, which never have 8th bit set *//* First check for no parity, most common case. */ if (((s[0] | s[1] | s[2] | s[3]) & 0x80) == 0) return(0); /* No parity or space parity *//* Check for mark parity */ if (((s[0] & s[1] & s[2] & s[3]) & 0x80) == 0x80) return('m'); /* Mark parity *//* Packet has some kind of parity *//* Make 7-bit copies of control fields */ s1 = s[1] & 0x7f; /* LEN */ s2 = s[2] & 0x7f; /* SEQ */ s3 = s[3] & 0x7f; /* TYPE *//* Check for even parity */ if ((s[0] == partab[s0]) && (s[1] == partab[s1]) && (s[2] == partab[s2]) && (s[3] == partab[s3])) return('e');/* Check for odd parity */ if ((s[0] != partab[s0]) && (s[1] != partab[s1]) && (s[2] != partab[s2]) && (s[3] != partab[s3])) return('o');/* Otherwise it's probably line noise. Let checksum calculation catch it. */ return(-1);}#endif /* PARSENSE *//* Check to make sure timeout intervals are long enough to allow maximum length packets to get through before the timer goes off. If not, the timeout interval is adjusted upwards. This routine is called at the beginning of a transaction, before we know anything about the delay characteristics of the line. It works only for serial communication devices; it trusts the speed reported by the operating system. Call with a timout interval. Returns it, adjusted if necessary.*/ intchktimo(timo,flag) int timo, flag; { long cps, z; int x, y; debug(F101,"chktimo timo","",timo); /* Timeout before adjustment */ debug(F101,"chktimo flag","",flag); if (flag) /* Don't change timeout if user */ return(timo); /* gave SET SEND TIMEOUT command. */ debug(F101,"chktimo spmax","",spmax); debug(F101,"chktimo urpsiz","",urpsiz); speed = ttgspd(); /* Get current speed. */ if (speed > 0L && !network) { cps = speed / 10L; /* Convert to chars per second */ if (cps > 0L) { long plen; /* Maximum of send and rcv pkt size */ z = cps * (long) timo; /* Chars per timeout interval */ z -= z / 10L; /* Less 10 percent */ plen = spmax; if (urpsiz > spmax) plen = urpsiz; debug(F101,"chktimo plen","",plen); if (z < plen) { /* Compare with packet size */ x = (int) ((long) plen / cps); /* Adjust if necessary */ y = x / 10; /* Add 10 percent for safety */ if (y < 2) y = 2; /* Or 2 seconds, whichever is more */ x += y; if (x > timo) /* If this is greater than current */ timo = x; /* timeout, change the timeout */ debug(F101,"chktimo new timo","",timo); } } } return(timo);}/* S P A C K -- Construct and send a packet *//* spack() sends a packet of the given type, sequence number n, with len data characters pointed to by d, in either a regular or extended- length packet, depending on len. Returns the number of bytes actually sent, or else -1 upon failure. Uses global npad, padch, mystch, bctu, data. Leaves packet fully built and null-terminated for later retransmission by resend(). Updates global sndpktl (send-packet length). NOTE: The global pointer "data" is assumed to point into the 7th position of a character array (presumably in packet buffer for the current packet). It was used by getpkt() to build the packet data field. spack() fills in the header to the left of the data pointer (the data pointer is defined in getsbuf() in ckcfn3.c). If the address "d" is the same as "data", then the packet's data field has been built "in place" and need not be copied.*/int#ifdef CK_ANSICspack(char pkttyp, int n, int len, CHAR *d)#elsespack(pkttyp,n,len,d) char pkttyp; int n, len; CHAR *d;#endif /* CK_ANSIC *//* spack */ { register int i; int j, k, lp, longpkt, copy; register CHAR *cp, *mydata; unsigned crc; debug(F101,"spack n","",n); debug(F111," data",data,data); debug(F101," d","",d); debug(F101," len","",len); copy = (d != data); /* Flag whether data must be copied */ longpkt = (len + bctl + 2) > 94; /* Decide whether it's a long packet */ mydata = data - 7 + (longpkt ? 0 : 3); /* Starting position of header */ debug(F101," mydata","",mydata); k = sseqtbl[n]; /* Packet structure info for pkt n */ debug(F101," sseqtbl[n]","",k); if (k < 0) { debug(F101,"spack sending packet out of window","",n); } else { /* Record packet info */ s_pkt[k].pk_adr = mydata; /* Remember address of packet. */ s_pkt[k].pk_seq = n; /* Record sequence number */ s_pkt[k].pk_typ = pkttyp; /* Record packet type */ } spktl = 0; /* Initialize length of this packet */ i = 0; /* and position in packet. *//* Now fill the packet */ mydata[i++] = mystch; /* MARK */ lp = i++; /* Position of LEN, fill in later */ mydata[i++] = tochar(n); /* SEQ field */ mydata[i++] = pkttyp; /* TYPE field */ j = len + bctl; /* Length of data + block check */ if (longpkt) { /* Long packet? */ int x; /* Work around SCO Xenix/286 */ x = 95; /* compiler bug... */ x = j / 95; mydata[lp] = tochar(0); /* Yes, set LEN to zero */ mydata[i++] = tochar(x); /* High part */ mydata[i++] = tochar(j % 95); /* Low part */ mydata[i] = '\0'; /* Header checksum */ mydata[i++] = tochar(chk1(mydata+lp)); } else mydata[lp] = tochar(j+2); /* Normal LEN */ if (copy) /* Data field built in place? */ for ( ; len--; i++) mydata[i] = *d++; /* No, must copy. */ else /* Otherwise, */ i += len; /* Just skip past data field. */ mydata[i] = '\0'; /* Null-terminate for checksum calc. */ switch (bctu) { /* Block check */ case 1: /* 1 = 6-bit chksum */ mydata[i++] = tochar(chk1(mydata+lp)); break; case 2: /* 2 = 12-bit chksum */ j = chk2(mydata+lp); mydata[i++] = (unsigned)tochar((j >> 6) & 077); mydata[i++] = (unsigned)tochar(j & 077); break; case 3: /* 3 = 16-bit CRC */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -