📄 ckcfn2.c
字号:
freerpkt(rsn); /* Free NAK's buffer */ x = resend(winlo); /* Resend current packet */ if (x < 0) { type = 'E'; errpkt(pktmsg); break; } else continue; /* Resend ok, go read another packet */ } else { /* Other cases, just 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);#ifdef NEWDPL /* Reduce prevailing packet length */ x = sseqtbl[rsn]; /* Length of packet that was NAK'd */ if (x > -1) { /* If it's a Data packet we've sent */ if (s_pkt[x].pk_typ == 'D') { spsiz = (s_pkt[x].pk_len + 8) >> 1; /* Halve length */#ifdef COMMENT /* This might be a good idea -- haven't tried it ... */ if (bestlen > 0 && spsiz > bestlen) spsiz = bestlen;#endif /* COMMENT */ if (spsiz < 20) spsiz = 20; debug(F101,"input N cut packet length","",spsiz); } }#endif /* NEWDPL */ 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. */ 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(pktmsg); 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(pktmsg); 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 the S or I */ } rsn = x; /* Else, treat NAK(n+1) as ACK(n) */ nak2ack = 1; /* Go back and process the ACK */ continue; } 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 *)pktmsg,"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() while() loop */ if (wslots == 1) { debug(F100,"input about to flush","",0); ttflui(); /* Got what we want, clear input buffer. */ }#ifndef NEWDPL if (!nakstate) /* When sending */ rcalcpsz(); /* recalculate size every packet */#endif /* NEWDPL */ debug(F000,"input returning type","",type); return(rcvtyp = 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#ifdef TCPSOCKET || (network && /* TELNET BINARY MODE */ (ttnproto == NP_TELNET) && (me_binary) )#endif /* TCPSOCKET */ ) return((CHAR) (ch & 255)); else a = ch & 127; switch (parity) { case 'e': return(p_tbl[a]); /* Even */ case 'm': return((CHAR) (a | 128)); /* Mark */ case 'o': return((CHAR) (p_tbl[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] == p_tbl[s0]) && (s[1] == p_tbl[s1]) && (s[2] == p_tbl[s2]) && (s[3] == p_tbl[s3])) return('e');/* Check for odd parity */ if ((s[0] != p_tbl[s0]) && (s[1] != p_tbl[s1]) && (s[2] != p_tbl[s2]) && (s[3] != p_tbl[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, x, lp, longpkt, copy;#ifdef GETMSEC long t1, t2;#endif /* GETMSEC */ register CHAR *cp, *mydata; unsigned crc; debug(F101,"spack n","",n); debug(F111,"spack data",data,data); /* debug(F101,"spack d","",d); */ debug(F101,"spack 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 = j / 95; /* compiler bug... */ 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 */ crc = chk3(mydata+lp,parity); mydata[i++] = (unsigned)tochar(((crc & 0170000)) >> 12); mydata[i++] = (unsigned)tochar((crc >> 6) & 077); mydata[i++] = (unsigned)tochar(crc & 077); break; case 4: /* 2 = 12-bit chksum, blank-free */ j = chk2(mydata+lp); mydata[i++] = (unsigned)(tochar((unsigned)(((j >> 6) & 077) + 1))); mydata[i++] = (unsigned)(tochar((unsigned)((j & 077) + 1))); break; } mydata[i++] = seol; /* End of line (packet terminator) */#ifdef TCPSOCKET/* If TELNET connection and packet terminator is carriage return, we must stuff either LF or NUL, according to SET TELNET NEWLINE-MODE (tn_nlm), to meet the TELNET specification, unless user said RAW. If NEWLINE-MODE is set to LF instead of CR, we still send CR-NUL on a NVT connection and CR on a binary connection.*/ if (seol == CR && network && ttnproto == NP_TELNET) { switch (me_binary ? tn_b_nlm : tn_nlm) { /* NVT or BINARY */ case TNL_CR: break; case TNL_CRNUL: mydata[i++] = NUL ; break; case TNL_CRLF: mydata[i++] = LF ; break; } }#endif /* TCPSOCKET */ mydata[i] = '\0'; /* Terminate string */ logpkt('s',n,mydata); /* Log packet */ /* (PWP) add the parity quickly at the end */ switch (parity) { case 'e': /* Even */ for (cp = &mydata[i-1]; cp >= mydata; cp--) *cp = p_tbl[*cp]; break; case 'm': /* Mark */ for (cp = &mydata[i-1]; cp >= mydata; cp--) *cp |= 128; break; case 'o': /* Odd */ for (cp = &mydata[i-1]; cp >= mydata; cp--) *cp = p_tbl[*cp] ^ 128; break; case 's': /* Space */ for (cp = &mydata[i-1]; cp >= mydata; cp--) *cp &= 127; break; } if (pktpaus) msleep(pktpaus); /* Pause if requested */ if (npad) ttol(padbuf,npad); /* Send any padding */#ifdef CK_TIMERS if (pkttyp == 'N') srttbl[n > 0 ? n-1 : 63] = gtimer(); else srttbl[n] = gtimer();#endif /* CK_TIMERS */ spktl = i; /* Remember packet length */ if (k > -1) s_pkt[k].pk_len = spktl; /* also in packet info structure */#ifdef GETMSEC if (deblog) t1 = getmsec();#endif /* GETMSEC */ x = ttol(mydata,spktl); if (spktl > maxsend) maxsend = spktl;#ifdef GETMSEC if (deblog) { t2 = getmsec(); if (t2 > -1L && t1 > -1L) debug(F101,"spack ttol time","",t2-t1); else debug(F100,"spack ttol time error","",0); }#endif /* GETMSEC */ debug(F101,"spack ttol returns","",x); if (x < 0) return(x); sndtyp = pkttyp; /* Remember packet type for echos */ spackets++; /* Count it. */ flco += spktl; /* Count the characters */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -