📄 tcpstate.c
字号:
/***********************************************************************//* *//* Module: tcp_ip/tcp/tcpstate.c *//* Release: 2001.3 *//* Version: 2001.0 *//* Purpose: TCP Input 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 "../tcp_ipp.h"#include "tcp.h"#include "../ip/ip.h"/***********************************************************************//* Configuration *//***********************************************************************/#define FAST_RXMIT_THRES 3 /* fast retransmit threshold *//***********************************************************************//* Function Prototypes *//***********************************************************************/static void closed(void);static void listens(void);static void syn_sent(void);static void syn_rcvd(void);static void established(void);static void closing(void);static void fin_wait1(void);static void fin_wait2(void);static void close_wait(void);static void last_ack(void);static void time_wait(void);static void set_time_wait(void);static int ack_and_win(void);/***********************************************************************//* Global Variable Definitions *//***********************************************************************/void (*TcpSwitch[])(void) ={ NULL, /* SS_FREE */ closed, /* SS_CLOSED */ listens, /* SS_LISTEN */ syn_sent, /* SS_SYNSENT */ syn_rcvd, /* SS_SYNRCVD */ established, /* SS_ESTABLISHED */ fin_wait1, /* SS_FINWAIT1 */ fin_wait2, /* SS_FINWAIT2 */ close_wait, /* SS_CLOSEWAIT */ last_ack, /* SS_LASTACK */ closing, /* SS_CLOSING */ time_wait, /* SS_TIMEWAIT */};/***********************************************************************//* Local TCP State Function Definitions *//***********************************************************************//***********************************************************************//* closed: Do CLOSED state processing *//* *//***********************************************************************/static void closed(void){ /*-------------------------------------------------------------------*/ /* Any incoming segment generates a TCP reset. */ /*-------------------------------------------------------------------*/ TcpReset();}/***********************************************************************//* listens: Do LISTEN state processing *//* *//***********************************************************************/static void listens(void){ SOCKET newsock; Route *route; uint mss; /*-------------------------------------------------------------------*/ /* Ignore resets because no connection exists. */ /*-------------------------------------------------------------------*/ if (Net.Tcp->flags & TCPF_RST) return; /*-------------------------------------------------------------------*/ /* Send RESET unless incoming packet contains SYN and no ACK. */ /*-------------------------------------------------------------------*/ if ((Net.Tcp->flags & TCPF_ACK) || !(Net.Tcp->flags & TCPF_SYN)) { TcpReset(); return; } /*-------------------------------------------------------------------*/ /* Get new TCP socket and begin initializing it. */ /*-------------------------------------------------------------------*/ newsock = TcpNewSock(WITH_BUFS); if (newsock == NULL) return; ++Stats.TcpPassiveOpens; newsock->flags = (Sock->flags & SF_INHERITED) | TCPF_SYN | TCPF_ACK; newsock->state = SS_SYNRCVD; newsock->connect_timeo = Sock->connect_timeo; /*-------------------------------------------------------------------*/ /* Reserve parent until child is deleted or becomes established. */ /*-------------------------------------------------------------------*/ ++Sock->reserve_cnt; newsock->psock = Sock; /*-------------------------------------------------------------------*/ /* Copy IP addresses and port numbers to the new socket. */ /*-------------------------------------------------------------------*/ newsock->remote.sin_addr.s_addr = Net.Ip->src_ip; newsock->remote.sin_port = Net.Tcp->src_port; newsock->local.sin_addr.s_addr = Net.Ip->dst_ip; newsock->local.sin_port = Net.Tcp->dst_port; /*-------------------------------------------------------------------*/ /* Determine maximum receive segment size. */ /*-------------------------------------------------------------------*/ route = RtSearch(Net.Ip->src_ip); if (route == NULL) mss = 536; /* RFC 1122 */ else { mss = route->ni->mtu - (IPMHLEN + TCPMHLEN); if (mss > (newsock->rb_size >> 1)) mss = newsock->rb_size >> 1; } newsock->rcv_mss = mss; /*-------------------------------------------------------------------*/ /* Send MSS should have come to parent. If not, use receive MSS. */ /*-------------------------------------------------------------------*/ if (Sock->snd_mss) { newsock->snd_mss = min(Sock->snd_mss, mss); Sock->snd_mss = 0; /* reset server smss */ } else newsock->snd_mss = mss; /*-------------------------------------------------------------------*/ /* Initialize other socket data. */ /*-------------------------------------------------------------------*/ newsock->snd_cwnd = newsock->snd_mss; newsock->rd_nxt = newsock->rcv_nxt = Net.Tcp->seq_num + 1; newsock->snd_window = Net.Tcp->window; newsock->lw_seq = Net.Tcp->seq_num; /*-------------------------------------------------------------------*/ /* Initiate new socket's SYN response and acknowledgment. */ /*-------------------------------------------------------------------*/ TcpTryOut(newsock); /*-------------------------------------------------------------------*/ /* Start SYN_RCVD timer to expire after timeout. */ /*-------------------------------------------------------------------*/ NetTimerStart(&newsock->state_tmr, newsock->connect_timeo); /*-------------------------------------------------------------------*/ /* Ignore FINs in LISTEN. */ /*-------------------------------------------------------------------*/ Net.Tcp->flags &= ~TCPF_FIN; /*-------------------------------------------------------------------*/ /* Advance sequence number due to SYN and process accompanying data. */ /*-------------------------------------------------------------------*/ ++Net.Tcp->seq_num; TcpData(newsock);}/***********************************************************************//* syn_sent: Do SYN_SENT state processing *//* *//***********************************************************************/static void syn_sent(void){ /*-------------------------------------------------------------------*/ /* Send RESET if incoming ACK specifies wrong sequence number. */ /*-------------------------------------------------------------------*/ if ((Net.Tcp->flags & TCPF_ACK) && (Net.Tcp->ack_num != Sock->snd_nxt)) { TcpReset(); return; } /*-------------------------------------------------------------------*/ /* Process incoming RESET by aborting socket. */ /*-------------------------------------------------------------------*/ if (Net.Tcp->flags & TCPF_RST) { TcpDrop(Sock, ECONNREFUSED); return; } /*-------------------------------------------------------------------*/ /* Waiting in this state for a SYN. */ /*-------------------------------------------------------------------*/ if ((Net.Tcp->flags & TCPF_SYN) == FALSE) return; /*-------------------------------------------------------------------*/ /* Initialize other socket data. */ /*-------------------------------------------------------------------*/ Sock->snd_cwnd = Sock->snd_mss; Sock->snd_window = Net.Tcp->window; Sock->lw_seq = Net.Tcp->seq_num; Sock->rd_nxt = Sock->rcv_nxt = Net.Tcp->seq_num + 1; Sock->flags |= (SF_SENDFLG | TCPF_ACK); /*-------------------------------------------------------------------*/ /* Ignore FINs in SYN_SENT. */ /*-------------------------------------------------------------------*/ Net.Tcp->flags &= ~TCPF_FIN; /*-------------------------------------------------------------------*/ /* Handle acknowledgments and window announcements. */ /*-------------------------------------------------------------------*/ ack_and_win(); /*-------------------------------------------------------------------*/ /* Advance sequence number due to SYN and process accompanying data. */ /*-------------------------------------------------------------------*/ ++Net.Tcp->seq_num; if (TcpData(Sock)) return; /*-------------------------------------------------------------------*/ /* If our SYN has not been ACKed, move to SYNRCVD. */ /*-------------------------------------------------------------------*/ if (Sock->flags & TCPF_SYN) { Sock->state = SS_SYNRCVD; } /*-------------------------------------------------------------------*/ /* Else, move to ESTABLISHED and wake task performing active open. */ /*-------------------------------------------------------------------*/ else { /*-----------------------------------------------------------------*/ /* Wake task that called connect(). */ /*-----------------------------------------------------------------*/ NetPostEvent(Sock, SE_OPENED); /*-----------------------------------------------------------------*/ /* Socket is now established and connected. */ /*-----------------------------------------------------------------*/ ++Stats.TcpCurrEstab; Sock->state = SS_ESTABLISHED; Sock->flags |= SF_CONNECTED; /*-----------------------------------------------------------------*/ /* Stop SYN acknowledgment timer. */ /*-----------------------------------------------------------------*/ NetTimerStop(&Sock->state_tmr); }}/***********************************************************************//* syn_rcvd: Do SYN_RCVD state input processing *//* *//***********************************************************************/static void syn_rcvd(void){ SOCKET psock = Sock->psock; /*-------------------------------------------------------------------*/ /* Delete socket for RST or SYN, respond with RST to SYN. */ /*-------------------------------------------------------------------*/ if (Net.Tcp->flags & (TCPF_RST | TCPF_SYN)) { if (Net.Tcp->flags & TCPF_SYN) TcpReset(); TcpDrop(Sock, ECONNREFUSED); return; } /*-------------------------------------------------------------------*/ /* Check for SYN acknowledgment, return if missing or absurd ACK. */ /*-------------------------------------------------------------------*/ if (ack_and_win()) return; /*-------------------------------------------------------------------*/ /* If no parent socket, this is a simultaneous active open. */ /*-------------------------------------------------------------------*/ if (psock == NULL) { NetPostEvent(Sock, SE_OPENED); } /*-------------------------------------------------------------------*/ /* Else this is a passive open. */ /*-------------------------------------------------------------------*/ else { /*-----------------------------------------------------------------*/ /* Send RST and delete if parent is not listening. */ /*-----------------------------------------------------------------*/ if (psock->state != SS_LISTEN) { TcpReset(); TcpDrop(Sock, ECONNABORTED); return; } /*-----------------------------------------------------------------*/ /* Ignore packet if listen queue is full. */ /*-----------------------------------------------------------------*/ if (psock->q_count >= psock->lis_backlog) return; /*-----------------------------------------------------------------*/ /* Otherwise, reserve socket and append to end of listen queue. */ /*-----------------------------------------------------------------*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -