📄 tcpomach.c
字号:
/***********************************************************************//* *//* Module: tcp_ip/tcp/tcpomach.c *//* Release: 2001.3 *//* Version: 2001.0 *//* Purpose: TCP Output State Machine Implementation *//* *//*---------------------------------------------------------------------*//* *//* Copyright 2001, Blunk Microsystems *//* ALL RIGHTS RESERVED *//* *//* Licensees have the non-exclusive right to use, modify, or extract *//* this computer program for software development at a single site. *//* This program may be resold or disseminated in executable format *//* only. The source code may not be redistributed or resold. *//* *//***********************************************************************/#include <string.h>#include "../tcp_ipp.h"#include "tcp.h"/***********************************************************************//* Symbol Definitions *//***********************************************************************/#define R2_RETRIES 12 /* time to drop connection */#define R1_RETRIES 3 /* time to advise IP *//***********************************************************************//* Local Function Definitions *//***********************************************************************//***********************************************************************//* sched_persist: Schedule persist window probes *//* *//* Input: sock = pointer to socket control block *//* *//***********************************************************************/static void sched_persist(SOCKET sock){ int timeout = sock->persist_timeo; /*-------------------------------------------------------------------*/ /* Limit and exponentially increase timeout if it is not too large. */ /*-------------------------------------------------------------------*/ if (timeout >= MAX_PRS) timeout = MAX_PRS; else { if (timeout < MIN_PRS) timeout = MIN_PRS; sock->persist_timeo <<= 1; } /*-------------------------------------------------------------------*/ /* Schedule next window probe. */ /*-------------------------------------------------------------------*/ NetTimerStart(&sock->out_tmr, timeout);}/***********************************************************************//* Global Function Definitions *//***********************************************************************//***********************************************************************//* TcpOut: Handle messages to TCP output state machine *//* *//* Input: object = pointer to socket control block *//* *//* Note: Must increment reserve_cnt before calling TcpOut() *//* *//***********************************************************************/void TcpOut(void *object){ int inflight, unsent; SOCKET sock = object; /*-------------------------------------------------------------------*/ /* Count inflight data and unsent data. */ /*-------------------------------------------------------------------*/ inflight = sock->snd_nxt - sock->snt_una; unsent = sock->sb_count - inflight; /*-------------------------------------------------------------------*/ /* SYN and FIN also count, one each. */ /*-------------------------------------------------------------------*/ if (sock->flags & TCPF_SYN) ++unsent; if (sock->flags & SF_SNDFIN) ++unsent; /*-------------------------------------------------------------------*/ /* Check if there is no unsent data. */ /*-------------------------------------------------------------------*/ if (unsent == 0) { /*-----------------------------------------------------------------*/ /* Check if everything sent has been acknowledged. */ /*-----------------------------------------------------------------*/ if (inflight == 0) { /*---------------------------------------------------------------*/ /* If not "idle", set "idle" and start congestion window timer. */ /*---------------------------------------------------------------*/ if (sock->out_state != TCPO_IDLE) { sock->out_state = TCPO_IDLE; NetTimerStart(&sock->out_tmr, sock->retrans_timeo); } } } /*-------------------------------------------------------------------*/ /* Else check if state is "idle" or "transmitting". */ /*-------------------------------------------------------------------*/ else if (sock->out_state <= TCPO_XMIT) { int window, room; /*-----------------------------------------------------------------*/ /* If "idle", stop "idle" timer and change to "transmit". */ /*-----------------------------------------------------------------*/ if (sock->out_state == TCPO_IDLE) { sock->out_state = TCPO_XMIT; sock->flags &= ~SF_TIMING_RTT; sock->retrans_count = 0; NetTimerStop(&sock->out_tmr); } /*-----------------------------------------------------------------*/ /* Clip window to minimum of send window and congestion window. */ /*-----------------------------------------------------------------*/ window = min(sock->snd_window, sock->snd_cwnd); room = window - inflight; /*-----------------------------------------------------------------*/ /* Loop while full-size segments can be sent or unsent data fits */ /* in remaining room and either (1) Nagle algorithm is disabled, */ /* (2) segment will be sent anyway, (3) no new transmit data is */ /* coming, or (4) nothing is inflight. */ /*-----------------------------------------------------------------*/ while ((min(unsent, room) >= sock->snd_mss) || ((unsent <= room) && ((sock->flags & (SF_NODELAY | SF_SENDFLG | SF_SNDFIN)) || (inflight == 0)))) { /*---------------------------------------------------------------*/ /* Send segment, break if no transmit buffer or route available. */ /*---------------------------------------------------------------*/ if (TcpSendSeg(sock, room)) break; /*---------------------------------------------------------------*/ /* Recalculate amount inflight and unsent. Break if all sent. */ /*---------------------------------------------------------------*/ inflight = sock->snd_nxt - sock->snt_una; room = window - inflight; unsent = sock->sb_count - inflight; if (unsent <= 0) break; } /*-----------------------------------------------------------------*/ /* Check if nothing in flight and unsent data remains. */ /*-----------------------------------------------------------------*/ if ((inflight == 0) && unsent) { /*---------------------------------------------------------------*/ /* Change state to persist and and schedule first probe. */ /*---------------------------------------------------------------*/ sock->out_state = TCPO_PERSIST; sock->persist_timeo = sock->retrans_timeo; sched_persist(sock); } } /*-------------------------------------------------------------------*/ /* Send segment with no data if necessary flags have not been sent. */ /*-------------------------------------------------------------------*/ if (sock->flags & SF_SENDFLG) TcpSendSeg(sock, 0); /*-------------------------------------------------------------------*/ /* If transmitting, ensure retransmit timer is running. */ /*-------------------------------------------------------------------*/ if ((sock->out_state == TCPO_XMIT) && (sock->out_tmr.running == FALSE)) NetTimerStart(&sock->out_tmr, sock->retrans_timeo); /*-------------------------------------------------------------------*/ /* Release hold on socket. */ /*-------------------------------------------------------------------*/ SockRelease(sock);}/***********************************************************************//* TcpOutTimeout: Process TCP output timeouts *//* *//* Input: object = pointer to socket control block *//* *//***********************************************************************/void TcpOutTimeout(void *object){ SOCKET sock = object; /*-------------------------------------------------------------------*/ /* After a retransmission timeout, enforce slow start. */ /*-------------------------------------------------------------------*/ sock->snd_cwnd = sock->snd_mss; /*-------------------------------------------------------------------*/ /* Finished if output state is idle. */ /*-------------------------------------------------------------------*/ if (sock->out_state == TCPO_IDLE) return; /*-------------------------------------------------------------------*/ /* Check if more than R1_RETRIES have already been sent. */ /*-------------------------------------------------------------------*/ if (++sock->retrans_count > R1_RETRIES) { /*-----------------------------------------------------------------*/ /* Clear cached route. */ /*-----------------------------------------------------------------*/ sock->route = NULL; /*-----------------------------------------------------------------*/ /* Forcefully drop connection after R2 retries if not waiting for */ /* first acknowledgment (in which case connect() timeout applies). */ /*-----------------------------------------------------------------*/ if ((sock->retrans_count > R2_RETRIES) && ((sock->flags & TCPF_SYN) == 0)) { sock->flags |= TCPF_RST; TcpSendSeg(sock, 0); TcpDrop(sock, sock->soft_error ? sock->soft_error : ECONNABORTED); return; } } /*-------------------------------------------------------------------*/ /* Process timeout according to output state. */ /*-------------------------------------------------------------------*/ switch (sock->out_state) { case TCPO_PERSIST: { int length = max(1, sock->snd_window); /*---------------------------------------------------------------*/ /* Send persist window probe and schedule next probe. */ /*---------------------------------------------------------------*/ sock->snd_nxt = sock->snt_una; TcpSendSeg(sock, length); sched_persist(sock); break; } case TCPO_XMIT: /*---------------------------------------------------------------*/ /* Change state to retransmit. */ /*---------------------------------------------------------------*/ sock->out_state = TCPO_REXMT; /*---------------------------------------------------------------*/ /* Double timeout if first acknowledgment has not been received. */ /*---------------------------------------------------------------*/ if (sock->flags & TCPF_SYN) sock->retrans_timeo <<= 1; /*---------------------------------------------------------------*/ /* Initialize slow start threshold to amount of inflight data. */ /*---------------------------------------------------------------*/ sock->ssthresh = sock->snd_nxt - sock->snt_una; /*---------------------------------------------------------------*/ /* Fall through to perform first retransmission. */ /*---------------------------------------------------------------*/ /*lint -fallthrough */ case TCPO_REXMT: { int timeout; /*---------------------------------------------------------------*/ /* Set slow start threshold to max(half previous size, 2 MSS). */ /*---------------------------------------------------------------*/ sock->ssthresh = max(sock->ssthresh >> 1, sock->snd_mss << 1); /*---------------------------------------------------------------*/ /* Retransmit oldest unacknowledged segment. */ /*---------------------------------------------------------------*/ sock->snd_nxt = sock->snt_una; TcpSendSeg(sock, sock->snd_mss); ++Stats.TcpRetransSegs; /*---------------------------------------------------------------*/ /* Schedule next retransmission using Karn's algorithm. */ /*---------------------------------------------------------------*/ timeout = sock->retrans_timeo << 1; sock->retrans_timeo = min(timeout, MAX_RXT); NetTimerStart(&sock->out_tmr, sock->retrans_timeo); break; } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -