📄 ckcfn2.c
字号:
if (wslots > 1) { /* If we're doing windows, */ x = rseqtbl[winlo]; /* see if desired packet already in. */ debug(F101," winlo","",winlo); debug(F101," rseqtbl[winlo]","",rseqtbl[winlo]); if (x > -1) { /* Already there? */ if (r_pkt[x].pk_seq == winlo) { /* (double check) */ rsn = winlo; /* Yes, return its info */ debug(F101,"input return pre-stashed packet","",rsn); dumprbuf(); rdatap = r_pkt[x].pk_adr; /* like rpack would do. */ rln = (int)strlen((char *) rdatap); type = r_pkt[x].pk_typ; break; } } } type = rpack(); /* Try to read a packet. */ debug(F111,"input recv",(char *) rdatap,(int) type); while (type == 'e') { /* Handle echoes */ debug(F000,"echo discarded","",type); type = rpack(); } #ifndef OLDCHKINT if (type == 'z') { errpkt((CHAR *)"User cancelled."); strcpy((char *)pktmsg,"User cancelled."); type = 'E'; break; }#endif /* OLDCHKINT */ if (type < -1) return('q'); /* Ctrl-C or connection lost */ if (type < 0) { /* Receive window full */ /* Another thing to do here would be to delete */ /* the highest packet and NAK winlo. But that */ /* shouldn't be necessary since the other Kermit */ /* should not have sent a packet outside the window. */ debug(F101,"rpack receive window full","",0); dumprbuf(); errpkt((CHAR *)"Receive window full."); strcpy((char *)pktmsg,"Receive window full."); type = 'E'; break; } dumprbuf();#ifdef OLDCHKINT if (chkint() < 0) { /* Check for console interrupts. */ errpkt((CHAR *)"User cancelled."); strcpy((char *)pktmsg,"User cancelled."); type = 'E'; break; }#endif /* OLDCHKINT */ if (type == 'E') { debug(F101,"input got E, nakstate","",nakstate); break; /* Error packet */ } if (type == 'Q') { /* Crunched packet. */ crunched++; numerrs++;/* Packet arrived damaged. It was most likely the packet we were expecting next, so we send a NAK for that packet. Prior to 5A(189), we always NAK'd winlo here, but that was bad because if two (or more) different packets were damaged, we would keep NAKing the first one and never NAK the other ones, which could result in a lengthy series of timeouts. Now we NAK the oldest as-yet-unNAK'd missing packet.*/#ifdef CK_TIMERS rcvtimo++; /* Stretch the timeout a little */#endif /* CK_TIMERS */ z = (winlo + wslots) % 64; /* Search from winlo to z */ debug(F101,"ZZZ crunched z","",z); nf = 0; /* NAK flag not set yet */ for (x = winlo; x != z; x = (x + 1) % 64) { debug(F101,"ZZZ x","",x); if (rseqtbl[x] > -1) /* Have I received packet x? */ continue; /* Yes, go on. */ debug(F101,"ZZZ x not recd yet","",x); pi = sseqtbl[x]; /* No, have I NAK'd it yet? */ if (pi < 0 || s_pkt[pi].pk_rtr == 0) { debug(F101,"ZZZ x not NAK'd yet","",x); nack(x); /* No, NAK it now. */ nf = 1; /* Flag that I did. */ break; } } if (!nf) { /* If we didn't NAK anything above, */ debug(F101,"ZZZ NAKing winlo","",winlo); if (nack(winlo) < 0) { /* we have to NAK winlo (again) */ errpkt((CHAR *)"Too many retries."); /* Too many */ strcpy((char *)pktmsg,"Timed out."); /* Give up */ type = 'E'; break; } } continue; } if (type == 'T') { /* Timeout */#ifdef CK_TIMERS rcvtimo++; /* Stretch the timeout a little */#endif /* CK_TIMERS */ timeouts++; debug(F101,"input receive-state timeout, winlo","",winlo); /* NAK only the packet at window-low */ debug(F101,"input sending NAK for winlo","",winlo); if (ttchk() > 0) /* Don't give up if there is still */ continue; /* something to read. */ if (nack(winlo) < 0) { debug(F101,"input sent too many naks","",winlo); errpkt((CHAR *)"Too many retries."); strcpy((char *)pktmsg,"Sent too many NAKs."); type = 'E'; break; } else continue; } if (rsn == winlo) { /* Got the packet we want, done. */#ifdef CK_TIMERS if (rttflg) /* Dynamic round trip timers? */ getrtt(nakstate, rsn); /* yes, do it. */#endif /* CK_TIMERS */ debug(F101,"input rsn=winlo","",rsn); break; } /* Got a packet out of order. */ debug(F101,"input recv got packet out of order","",rsn); k = rseqtbl[rsn]; /* Get window slot of this packet. */ debug(F101,"input recv rseqtbl[rsn]","",k); if (k < 0) { debug(F101,"input recv can't find index for rcvd pkt","",rsn); /* Was "Internal error 21" */ errpkt((CHAR *)"Sliding windows protocol error."); strcpy((char *)pktmsg,"Sliding windows protocol error."); type = 'E'; break; } y = chkwin(rsn,winlo,wslots); /* See what window it's in. */ debug(F101,"input recv chkwin","",y); if (y == 1) { /* From previous window. */ resend(rsn); /* Resend the ACK (might have data) */ freerpkt(rsn); /* Get rid of received packet */ continue; } else { /* In this window or out of range */ if (y < 0) /* If out of range entirely, */ freerpkt(rsn); /* release its buffer */#ifdef COMMENT /* Ignore this and read what comes afterwards... *//* We have received a packet, but not the one we want. It would seem to make sense to always send a NAK for the most desired packet (winlo). But consider this scenario: a packet arrived damaged so we NAK'd it above; then packets winlo+1, winlo+2, ... winlo+n arrive, each one making us send another NAK for winlo, so the other Kermit gets n NAKs for winlo, and either would have to resend it n times, or if n > retry limit, give up because of too many retries. So we compromise: If a packet arrives that is not the most desired packet (winlo), we NAK winlo, BUT ONLY IF it has not been NAK'd before.*/ x = sseqtbl[winlo]; /* Get index of most desired packet */ if (s_pkt[x].pk_rtr == 0 || /* Not NAK'd before? */ rbufnum < 1) { /* Or receive window full? */ if (nack(winlo) < 0) { /* One or both, so NAK it now. */ errpkt((CHAR *)"Too many retries."); /* Too many */ strcpy((char *)pktmsg,"Timed out."); /* Give up */ type = 'E'; break; } else continue; } else continue;#endif /* COMMENT *//* In version 5A(189), the strategy was revised to send NAKs for the oldest missing packet that had not been NAK'd before, which requires a search. Thus, if winlo was already NAK'd, instead of doing nothing, we send a NAK for the "lowest" as-yet-unNAK'd missing packet. If our receive window is full, however, we have no choice but to NAK winlo:*/ debug(F101,"XXX checking rbufnum","",rbufnum); if (rbufnum < 1) { /* Receive window full? */ debug(F101,"XXX out of buffers","",rbufnum); /* Yes */ if (nack(winlo) < 0) { /* No choice, must NAK winlo. */ errpkt((CHAR *)"Too many retries."); /* Too many */ strcpy((char *)pktmsg,"Timed out."); /* Give up */ type = 'E'; break; } else continue; }/* Receive window not full. This is a packet in the current window but it is not the desired packet at winlo. So therefore there are gaps before this packet. So we find the "lowest" unNAK'd missing packet, if any, between winlo and this one, and NAK it. If there are no as-yet-unNAK'd missing packets in the window, then we send nothing and go wait for another packet. In theory, this could result in a timeout, but in practice it is likely that the already-NAK'd missing packets are already on their way. Note, we do not NAK ahead of ourselves, as that only creates unnecessary retransmissions.*/ debug(F101,"XXX winlo","",winlo); for (x = winlo; x != rsn; x = (x + 1) % 64) { debug(F101,"XXX x","",x); if (rseqtbl[x] > -1) /* Have I received packet x? */ continue; /* Yes, check next sequence number. */ debug(F101,"XXX missing pkt","",x); pi = sseqtbl[x]; /* No, have I NAK'd it yet? */ if (pi < 0 || s_pkt[pi].pk_rtr == 0) { nack(x); /* No, NAK it now. */ debug(F101,"XXX nak","",x); break; } } }/*!!!*/ } else { /* Otherwise file sender... */ if (!nak2ack) { /* NAK(n+1) = ACK(n) */ 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(); } #ifndef OLDCHKINT if (type == 'z') { errpkt((CHAR *)"User cancelled."); strcpy((char *)pktmsg,"User cancelled."); type = 'E'; break; }#endif /* OLDCHKINT */ if (type == -2) return('q'); if (type == -1) { errpkt((CHAR *)"Receive window full"); /* was "internal */ debug(F101," wslots","",wslots); /* error 18" */ debug(F101," winlo","",winlo); debug(F101," pktnum","",pktnum); dumprbuf(); strcpy((char *)pktmsg,"Can't allocate receive buffer"); type = 'E'; break; } dumprbuf(); /* Debugging */#ifdef OLDCHKINT if (chkint() < 0) { /* Check for console interrupts. */ errpkt((CHAR *)"User cancelled."); strcpy((char *)pktmsg,"User cancelled."); return(type = 'E'); }#endif /* OLDCHKINT */ /* 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(pktmsg); 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(pktmsg); return(type = 'E'); }#ifdef NEWDPL /* Reduce prevailing packet length */ x = sseqtbl[winlo]; /* Get length of packet we want ACKd */ if (x > -1) { /* Only if we have a valid index */ if (s_pkt[x].pk_typ == 'D') { /* only for D packets */ spsiz = (s_pkt[x].pk_len + 8) >> 1; /* halve it */ if (spsiz < 20) spsiz = 20; /* within reason */ debug(F101,"input T cut packet length","",spsiz); } }#endif /* NEWDPL */ continue; } } /* Got an actual normal packet */ nak2ack = 0; /* Unset this flag. */ 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 */ if (spackets < 4) /* Error counter doesn't count */ numerrs = 0; /* until data phase. */ sacktbl[rsn]++; /* Mark the packet as ACK'd */ x = sseqtbl[rsn]; /* Get ACK'd packet's buffer index */ debug(F101,"bestlen ack x","",x);#ifdef NEWDPL if (x > -1) { acktype = s_pkt[x].pk_typ; /* Get type */ debug(F000,"bestlen ack type","",acktype); if (acktype == 'D') { /* Adjust data packet length */ if (spsiz > bestlen) { bestlen = spsiz; debug(F101,"bestlen B","",bestlen); }#ifdef DEBUG if (deblog) { debug(F101,"bestlen retry","",s_pkt[x].pk_rtr); debug(F101,"bestlen len","",s_pkt[x].pk_len); debug(F101,"bestlen spackets","",spackets); }#endif /* DEBUG */ /* Set new best length */ if (s_pkt[x].pk_rtr == 0 && s_pkt[x].pk_len + 8 > bestlen) { bestlen = s_pkt[x].pk_len + 8; if (bestlen > spmax) bestlen = spmax; debug(F101,"bestlen A","",bestlen); }#ifdef DEBUG if (deblog) { debug(F101,"bestlen wslots","",wslots); debug(F101,"bestlen maxsend","",maxsend); }#endif /* DEBUG */ /* Slow start */ if (slostart && (maxsend <= spmax) && (rpackets < 11) && (numerrs == 0)) { spsiz = spsiz << 1; debug(F101,"bestlen spsiz A","",spsiz); /* Creep up to best length */ } else if ((spackets > 5) && (spsiz < bestlen - 8)) { spsiz += (bestlen - spsiz) / 3; debug(F101,"bestlen spsiz B","",spsiz); /* Push the envelope */ } else if ((spackets % (wslots + 1) == 0) && (spackets > 6) && (bestlen < spmax - 8) && (spsiz < spmax)) { spsiz += (spmax - bestlen) / 3; debug(F101,"bestlen spsiz C","",spsiz); } /* But not too far */ if (spsiz > spmax) { spsiz = spmax; debug(F101,"bestlen spsiz D","",spsiz); } } }#endif /* NEWDPL */#ifdef CK_TIMERS if (rttflg) /* If doing dynamic timers */ getrtt(nakstate, rsn); /* call routine to set it. */#endif /* CK_TIMERS *//* 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 if (y == 1 && wslots < 2) { /* (190) ACK for previous */ numerrs++; /* == NAK for current, count error */ debug(F101,"input send ACK for previous","",rsn);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -