LWIP完全剖析详解之core/tcp_in.c,主要是对接收到的TCP 的pcb包和buffer做处理.
原文来自csdn博客:http://blog.csdn.net/lizhiliang06/article/details/8759857
/**
* @file
* Transmission Control Protocol, incoming traffic
*
* The input processing functions of the TCP layer.
*
* These functions are generally called in the order (ip_input() ->)
* tcp_input() -> * tcp_process() -> tcp_receive() (-> application).
* 传输控制协议,入局通信量
* 输入处理TCP层函数.
* 这些函数一般被按照下面顺便被调用(ip_input() ->)
* tcp_input() -> * tcp_process() -> tcp_receive() (-> application).
*/
#include "lwip/opt.h"//选项头文件,lwip一些配置的选项包含在opt.h,debug开启和内存大小等配置信息
#if LWIP_TCP /* don't build if not configured for use in lwipopts.h *//*如果在lwipopts.h没有配置LWIP_TCP这项,则不编译TCP这个文件*/
#include "lwip/tcp.h"//包含tcp.c里面定义的函数声明和所用到的宏
#include "lwip/def.h"//定义项头文件,包括一些宏
#include "lwip/ip_addr.h"//包含IP地址类型的宏,IP地址的一些设置和判断
#include "lwip/netif.h"//网络接口的一些结构体和一些参数设置
#include "lwip/mem.h"//内存头文件,包括一些宏,内存大小,申请内存,内存对齐
#include "lwip/memp.h" //内存池头文件,包含内存申请,内存释放
#include "lwip/inet.h" //网络地址的一些转换,例如BCD码的转换
#include "lwip/inet_chksum.h"//包含了网络包的校验和声明
#include "lwip/stats.h"//网络状态信息打印
#include "lwip/snmp.h"//snmp网络函数的声明
#include "arch/perf.h"
/* These variables are global to all functions involved in the input
processing of TCP segments. They are set by the tcp_input()
function. */
/* 这些值对所有的函数有关的TCP段的输入进度来说是全局.
他们都在tcp_input()函数里做设置
*/
static struct tcp_seg inseg;//TCP 段
static struct tcp_hdr *tcphdr; //TCP 头
static struct ip_hdr *iphdr;//IP头
static u32_t seqno, ackno;//序列号,应答号
static u8_t flags;//标识
static u16_t tcplen;//TCP长度
static u8_t recv_flags;//接收标识
static struct pbuf *recv_data;//接收数据
struct tcp_pcb *tcp_input_pcb;//TCP 输入PCB
/* Forward declarations. */
/* 前面声明. */
static err_t tcp_process(struct tcp_pcb *pcb);//TCP处理
static u8_t tcp_receive(struct tcp_pcb *pcb);//TCP接收函数
static void tcp_parseopt(struct tcp_pcb *pcb);//TCP选项的分析
static err_t tcp_listen_input(struct tcp_pcb_listen *pcb);//TCP监听输入
static err_t tcp_timewait_input(struct tcp_pcb *pcb);//TCP的等待输入
/**
* The initial input processing of TCP. It verifies the TCP header, demultiplexes
* the segment between the PCBs and passes it on to tcp_process(), which implements
* the TCP finite state machine. This function is called by the IP layer (in
* ip_input()).
*
* @param p received TCP segment to process (p->payload pointing to the IP header)
* @param inp network interface on which this segment was received
*/
/**
* TCP初始化输入处理,它验证了TCP头,在PCB和tcp_process()传递段之间解复用,它实现了TCP
* 有限状态机,这个函数被IP层调用
* @参数p:处理接收的TCP段(指向IP头的负载)
* @参数inp:接收段的网络接口
*/
void
tcp_input(struct pbuf *p, struct netif *inp)
{
struct tcp_pcb *pcb, *prev;
struct tcp_pcb_listen *lpcb;
u8_t hdrlen;
err_t err;
PERF_START;
TCP_STATS_INC(tcp.recv);//状态加1
snmp_inc_tcpinsegs();//tcp输入段加1
iphdr = p->payload;//负载的数据
/*
包头长度(IHL):4位,IP协议包头的长度,指明IPv4协议包头长度的字节数包含多少个32位。
由于IPv4的包头可能包含可变数量的可选 项,所以这个字段可以用来确定IPv4数据报中数据部分的偏移位置。
IPv4包头的最小长度是20个字节,因此IHL这个字段的最小值用十进制表示就是5 (5x4 = 20字节)。
就是说,它表示的是包头的总字节数是4字节的倍数 */
tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4);//略过包头
#if TCP_INPUT_DEBUG
tcp_debug_print(tcphdr);
#endif
/* remove header from payload */
/* 从负载中移除包头 */
if (pbuf_header(p, -((s16_t)(IPH_HL(iphdr) * 4))) || (p->tot_len < sizeof(struct tcp_hdr))) {
/* drop short packets */
/* 终止短包 */
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len));
TCP_STATS_INC(tcp.lenerr);//错误长度计数加1
TCP_STATS_INC(tcp.drop);//终止tcp计数加1
snmp_inc_tcpinerrs();
pbuf_free(p);//释放buffer
return;
}
/* Don't even process incoming broadcasts/multicasts. */
/* 甚至不处理广播和主播. */
if (ip_addr_isbroadcast(&(iphdr->dest), inp) ||
ip_addr_ismulticast(&(iphdr->dest))) {
TCP_STATS_INC(tcp.proterr);//协议错误计数加1
TCP_STATS_INC(tcp.drop);//终止计数加1
snmp_inc_tcpinerrs();
pbuf_free(p);//释放buffer
return;
}
#if CHECKSUM_CHECK_TCP
/* Verify TCP checksum. */
/* 验证TCP校验和. */
if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),
(struct ip_addr *)&(iphdr->dest),
IP_PROTO_TCP, p->tot_len) != 0) {
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n",
inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src), (struct ip_addr *)&(iphdr->dest),
IP_PROTO_TCP, p->tot_len)));
#if TCP_DEBUG
tcp_debug_print(tcphdr);
#endif /* TCP_DEBUG */
TCP_STATS_INC(tcp.chkerr);//校验错误计数加1
TCP_STATS_INC(tcp.drop); //终止计数加1
snmp_inc_tcpinerrs();
pbuf_free(p);//释放buffer
return;
}
#endif
/* Move the payload pointer in the pbuf so that it points to the
TCP data instead of the TCP header. */
/* 在pbuf上移动负载指针.它指向TCP数据替代TCP头 */
hdrlen = TCPH_HDRLEN(tcphdr);//计算头的长度
if(pbuf_header(p, -(hdrlen * 4))){//跨过TCP头,返回0为成功,否则
/* drop short packets */
/* 终止短包*/
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet\n"));
TCP_STATS_INC(tcp.lenerr);//tcp长度错误计数加1
TCP_STATS_INC(tcp.drop);//tcp终止计数加1
snmp_inc_tcpinerrs();
pbuf_free(p);//释放buffer
return;
}
/* Convert fields in TCP header to host byte order. */
/* 转换TCP头的区域到主机字节序. */
tcphdr->src = ntohs(tcphdr->src);//转换源地址
tcphdr->dest = ntohs(tcphdr->dest);//转换目的地址
seqno = tcphdr->seqno = ntohl(tcphdr->seqno);//转换序列号
ackno = tcphdr->ackno = ntohl(tcphdr->ackno);//转换应答号
tcphdr->wnd = ntohs(tcphdr->wnd);//转换tcp窗口
/*
标志:是一个3位的控制字段,包含:
保留位:1位
不分段位:1位,取值:0(允许数据报分段)、1(数据报不能分段)
更多段位:1位,取值:0(数据包后面没有包,该包为最后的包)、1(数据包后面有更多的包)
*/
flags = TCPH_FLAGS(tcphdr);//得到tcp头的标志
tcplen = p->tot_len + ((flags & (TCP_FIN | TCP_SYN)) ? 1 : 0);//?????
/* Demultiplex an incoming segment. First, we check if it is destined
for an active connection. */
/*进来段解复用,首先,我们检查是否一定要激活一个连接. */
prev = NULL;
for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {//遍历激活列表
LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED);
LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);
LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN);
if (pcb->remote_port == tcphdr->src &&
pcb->local_port == tcphdr->dest &&
ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) &&
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) {//检查相关的地址
/* Move this PCB to the front of the list so that subsequent
lookups will be faster (we exploit locality in TCP segment
arrivals). */
/* 移动这个PCB到列表前面,因此后来的查询将更快(我们利用本地的TCP段). */
LWIP_ASSERT("tcp_input: pcb->next != pcb (before cache)", pcb->next != pcb);
if (prev != NULL) {//如果前面一个节点不为空
prev->next = pcb->next;
pcb->next = tcp_active_pcbs;
tcp_active_pcbs = pcb;//pcb插入最前面
}
LWIP_ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb);
break;
}
prev = pcb;//prev指向pcb
}
if (pcb == NULL) {
/* If it did not go to an active connection, we check the connections
in the TIME-WAIT state. */
/* 如果没有到一个激活链接,我们在TIME-WAIT状态下检查连接. */
for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {//遍历等待状态下的pcb
LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
if (pcb->remote_port == tcphdr->src &&
pcb->local_port == tcphdr->dest &&
ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) &&
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) {
/* We don't really care enough to move this PCB to the front
of the list since we are not very likely to receive that
many segments for connections in TIME-WAIT. */
/* 我们不真正在乎移动这个PCB到列表的最前段,因为我们不轻易接受很多在TIME_WAIT状态连接下的段. */
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for TIME_WAITing connection.\n"));
tcp_timewait_input(pcb);//发送tcp timewait 的包
pbuf_free(p);//释放
return;
}
}
/* Finally, if we still did not get a match, we check all PCBs that
are LISTENing for incoming connections. */
/* 最后,如果我们还没有得到合适的,我们检查所有的进来监听的PCB. */
prev = NULL;
for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
if ((ip_addr_isany(&(lpcb->local_ip)) ||
ip_addr_cmp(&(lpcb->local_ip), &(iphdr->dest))) &&
lpcb->local_port == tcphdr->dest) {
/* Move this PCB to the front of the list so that subsequent
lookups will be faster (we exploit locality in TCP segment
arrivals). */
/* 移动这个PCB到列表的最前面.所以之后的查询将会更快 */
if (prev != NULL) {
((struct tcp_pcb_listen *)prev)->next = lpcb->next;
/* our successor is the remainder of the listening list */
/* 我们后继的会是监听列表所剩余的*/
lpcb->next = tcp_listen_pcbs.listen_pcbs;
/* put this listening pcb at the head of the listening list */
/* 吧这个监听pcb放入监听列表的头 */
tcp_listen_pcbs.listen_pcbs = lpcb;
}
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n"));
tcp_listen_input(lpcb);//发出tcp监听数据包
pbuf_free(p);//释放 buffer
return;
}
prev = (struct tcp_pcb *)lpcb;//prev指向pcb块
}
}
#if TCP_INPUT_DEBUG
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("+-+-+-+-+-+-+-+-+-+-+-+-+-+- tcp_input: flags "));
tcp_debug_print_flags(TCPH_FLAGS(tcphdr));
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n"));
#endif /* TCP_INPUT_DEBUG */
if (pcb != NULL) {
/* The incoming segment belongs to a connection. */
/* 传入段属于一个连接. */
#if TCP_INPUT_DEBUG
#if TCP_DEBUG
tcp_debug_print_state(pcb->state);
#endif /* TCP_DEBUG */
#endif /* TCP_INPUT_DEBUG */
/* Set up a tcp_seg structure. */
/* 建立一个tcp_seg结构. */
inseg.next = NULL;
inseg.len = p->tot_len;//设置总长
inseg.dataptr = p->payload;//负载的buffer
inseg.p = p;//传入的pbuf
inseg.tcphdr = tcphdr;//tcp头
recv_data = NULL;//接收数据设置空
recv_flags = 0;//接收标志
/* If there is data which was previously "refused" by upper layer */
/* 如果有预先被上层拒绝的数据, */
if (pcb->refused_data != NULL) {
/* Notify again application with data previously received. */
/* 再次把之前接收的数据通知给应用. */
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n"));
TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);//pcb接收数据
if (err == ERR_OK) {
pcb->refused_data = NULL;
} else {
/* drop incoming packets, because pcb is "full" */
/* 丢弃传入的包,因为pcb已经满了*/
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n"));
TCP_STATS_INC(tcp.drop);//tcp丢弃计数加1
snmp_inc_tcpinerrs();
pbuf_free(p);//释放pbuf
return;
}
}
tcp_input_pcb = pcb;//输入pcb
err = tcp_process(pcb);//处理pcb
tcp_input_pcb = NULL;//输入pcb置空
/* A return value of ERR_ABRT means that tcp_abort() was called
and that the pcb has been freed. If so, we don't do anything. */
/* 一个ERR_ABRT的返回值意味着tcp_abort()被调用和pcb已经释放,假如这样,我们什么也不做 */
if (err != ERR_ABRT) {
if (recv_flags & TF_RESET) {
/* TF_RESET means that the connection was reset by the other
end. We then call the error callback to inform the
application that the connection is dead before we
deallocate the PCB. */
/* TF_RESET意味着连接被其它的终端重置.
我们调用错误的回调函数来告诉应用程连接已经在我们释放PCB之前死掉了*/
TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_RST);//执行错误事件的回调函数
tcp_pcb_remove(&tcp_active_pcbs, pcb);//删除激活pcb列表中的pcb
memp_free(MEMP_TCP_PCB, pcb);//释放内存
} else if (recv_flags & TF_CLOSED) {
/* The connection has been closed and we will deallocate the
PCB. */
/* 连接已经被关闭,我们将释放PCB. */
tcp_pcb_remove(&tcp_active_pcbs, pcb);
memp_free(MEMP_TCP_PCB, pcb);
} else {
err = ERR_OK;
/* If the application has registered a "sent" function to be
called when new send buffer space is available, we call it
now. */
/* 如果应用已经注册了一个"sent"被调用的函数,当一个新的send缓冲空间可用,我们现在就调用它. */
if (pcb->acked > 0) {
TCP_EVENT_SENT(pcb, pcb->acked, err);//执行发送函数事件
}
if (recv_data != NULL) {//收到数据为空?
//PSH标志 PSH 紧急位。当PSH=1时,要求发送方马上发送该分段,而接收方尽快的将报文交给应用层,不做队列处理。
if(flags & TCP_PSH) {
recv_data->flags |= PBUF_FLAG_PUSH;//这段buffer应该立即存起来
}
/* Notify application that data has been received. */
/* 告知应用数据已经被接收了. */
TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err);
/* If the upper layer can't receive this data, store it */
/* 如果上次不可以接收数据,则存起来 */
if (err != ERR_OK) {
pcb->refused_data = recv_data;//接受数据
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: keep incoming packet, because pcb is \"full\"\n"));
}
}
/* If a FIN segment was received, we call the callback
function with a NULL buffer to indicate EOF. */
/* 如果一个FIN段被接收,我们调用回调函数,空buffer表示EOF结束. */
if (recv_flags & TF_GOT_FIN) {
TCP_EVENT_RECV(pcb, NULL, ERR_OK, err);//pcb接收事件
}
/* If there were no errors, we try to send something out. */
/* 如果没有错误发生,我们尝试发送点东西出去. */
if (err == ERR_OK) {
tcp_output(pcb);//发送pcb
}
}
}
/* give up our reference to inseg.p */
/* 放弃我们的引用inseg.p */
if (inseg.p != NULL)
{
pbuf_free(inseg.p);//释放buffer
inseg.p = NULL;//置空
}
#if TCP_INPUT_DEBUG
#if TCP_DEBUG
tcp_debug_print_state(pcb->state);
#endif /* TCP_DEBUG */
#endif /* TCP_INPUT_DEBUG */
} else {
/* If no matching PCB was found, send a TCP RST (reset) to the
sender. */
/* 如果没有找到匹配的PCB,发送一个TCP复位给发送者. */
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n"));
if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) {
TCP_STATS_INC(tcp.proterr);//协议错误计数器加1
TCP_STATS_INC(tcp.drop);//tcp丢弃计数器加1
tcp_rst(ackno, seqno + tcplen,
&(iphdr->dest), &(iphdr->src),
tcphdr->dest, tcphdr->src);//发送TCP复位
}
pbuf_free(p);//释放pbuf
}
LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane());
PERF_STOP("tcp_input");
}
/**
* Called by tcp_input() when a segment arrives for a listening
* connection (from tcp_input()).
*
* @param pcb the tcp_pcb_listen for which a segment arrived
* @return ERR_OK if the segment was processed
* another err_t on error
*
* @note the return value is not (yet?) used in tcp_input()
* @note the segment which arrived is saved in global variables, therefore only the pcb
* involved is passed as a parameter to this function
*/
/**
* 但一个监听中的连接收到一个段到达的段,tcp_input()就会被调用
*@参数pcb:tcp_pcb_listen中一个到达的段
*@如果段处理了其他在错误中的错误类型则返回ERR_OK
*
*@注意返回值没有被使用在tcp_input()里面
* @注意到达的段被保存在全局变量里面,因此只有涉及到的pcb被作为参数传送到函数里面
*/
static err_t
tcp_listen_input(struct tcp_pcb_listen *pcb)
{
struct tcp_pcb *npcb;
err_t rc;
/* In the LISTEN state, we check for incoming SYN segments,
creates a new PCB, and responds with a SYN|ACK. */
/* 在监听状态,我们检查传入的SYN段,生成一个新的PCB,和返回一个SYN|ACK. */
if (flags & TCP_ACK) {
/* For incoming segments with the ACK flag set, respond with a
RST. */
/* 对传入段的ACK标志设置,返回一个RST标志. */
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n"));
tcp_rst(ackno + 1, seqno + tcplen,
&(iphdr->dest), &(iphdr->src),
tcphdr->dest, tcphdr->src);//发送重定位数据包
} else if (flags & TCP_SYN) {
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest));
#if TCP_LISTEN_BACKLOG
if (pcb->accepts_pending >= pcb->backlog) {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: listen backlog exceeded for port %"U16_F"\n", tcphdr->dest));
return ERR_ABRT;
}
#endif /* TCP_LISTEN_BACKLOG */
npcb = tcp_alloc(pcb->prio);//TCP分配新的PCB结构
/* If a new PCB could not be created (probably due to lack of memory),
we don't do anything, but rely on the sender will retransmit the
SYN at a time when we have more memory available. */
/* 如果一个新的PCB生成失败(可能由于缺少内存),我们什么也不做,但是依靠发送端假如有足够可用的内存将传送一次SYN. */
if (npcb == NULL) {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n"));
TCP_STATS_INC(tcp.memerr);//TCP内存错误计数加1
return ERR_MEM;
}
#if TCP_LISTEN_BACKLOG
pcb->accepts_pending++;
#endif /* TCP_LISTEN_BACKLOG */
/* Set up the new PCB. */
/* 建立新的PCB. */
ip_addr_set(&(npcb->local_ip), &(iphdr->dest));
npcb->local_port = pcb->local_port;
ip_addr_set(&(npcb->remote_ip), &(iphdr->src));
npcb->remote_port = tcphdr->src;
npcb->state = SYN_RCVD;
npcb->rcv_nxt = seqno + 1;
npcb->rcv_ann_right_edge = npcb->rcv_nxt;
npcb->snd_wnd = tcphdr->wnd;
npcb->ssthresh = npcb->snd_wnd;
/* initialise to seqno-1 to force window update */
/* 初始化序列号-1来强制窗口更新 */
npcb->snd_wl1 = seqno - 1;
npcb->callback_arg = pcb->callback_arg;
#if LWIP_CALLBACK_API
npcb->accept = pcb->accept;
#endif /* LWIP_CALLBACK_API */
/* inherit socket options */
/* 集成socket选项 */
npcb->so_options = pcb->so_options & (SOF_DEBUG|SOF_DONTROUTE|SOF_KEEPALIVE|SOF_OOBINLINE|SOF_LINGER);
/* Register the new PCB so that we can begin receiving segments
for it. */
/* 注册新的PCB,这样我们可以开始给让接收段. */
TCP_REG(&tcp_active_pcbs, npcb);
/* Parse any options in the SYN. */
/* 分析在SYN的任何选项. */
tcp_parseopt(npcb);
#if TCP_CALCULATE_EFF_SEND_MSS
npcb->mss = tcp_eff_send_mss(npcb->mss, &(npcb->remote_ip));//发送有效的最大段大小
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
snmp_inc_tcppassiveopens();
/* Send a SYN|ACK together with the MSS option. */
/* 发送一个SYN|ACK和MSS选项. */
rc = tcp_enqueue(npcb, NULL, 0, TCP_SYN | TCP_ACK, 0, TF_SEG_OPTS_MSS
#if LWIP_TCP_TIMESTAMPS
/* and maybe include the TIMESTAMP option */
| (npcb->flags & TF_TIMESTAMP ? TF_SEG_OPTS_TS : 0)
#endif
);
if (rc != ERR_OK) {
tcp_abandon(npcb, 0);//放弃新的pcb
return rc;
}
return tcp_output(npcb);//发送新的pcb数据包
}
return ERR_OK;
}
/**
* Called by tcp_input() when a segment arrives for a connection in
* TIME_WAIT.
*
* @param pcb the tcp_pcb for which a segment arrived
*
* @note the segment which arrived is saved in global variables, therefore only the pcb
* involved is passed as a parameter to this function
*/
/**
* 当一个段在TIME_WAIT状态的连接到达时调用tcp_input()
* @ 参数pcb:段到达的pcb
* @ 注意到达的段被存为全局变量,一次只有设计到的pcb才被作为参数传入函数
*/
static err_t
tcp_timewait_input(struct tcp_pcb *pcb)
{
if (TCP_SEQ_GT(seqno + tcplen, pcb->rcv_nxt)) {//序列号+TCP长度大于下个启动的应答
pcb->rcv_nxt = seqno + tcplen;
}
if (tcplen > 0) {
tcp_ack_now(pcb);//发送TCP应答包
}
return tcp_output(pcb);
}
/**
* Implements the TCP state machine. Called by tcp_input. In some
* states tcp_receive() is called to receive data. The tcp_seg
* argument will be freed by the caller (tcp_input()) unless the
* recv_data pointer in the pcb is set.
*
* @param pcb the tcp_pcb for which a segment arrived
*
* @note the segment which arrived is saved in global variables, therefore only the pcb
* involved is passed as a parameter to this function
*/
/**
* 实现TCP状态机制,被tcp_input()调用,在一些状态中 tcp_receive()被
* 调用来接收数据,tcp段参数将被调用者(tcp_input())释放,除非recv_data指针在pcb里面
* 设置了
* @参数pcb:一个段到达的tcp_pcb
*
* @注意:段到达存在全局变量里面,
* 因此只有解决了的pcb作为一个参数传到这个函数
*/
static err_t
tcp_process(struct tcp_pcb *pcb)
{
struct tcp_seg *rseg;
u8_t acceptable = 0;
err_t err;
err = ERR_OK;
/* Process incoming RST segments. */
/* 处理进来的RST复位段. */
if (flags & TCP_RST) {
/* First, determine if the reset is acceptable. */
/* 首先,确定复位是否接受. */
if (pcb->state == SYN_SENT) {
if (ackno == pcb->snd_nxt) {
acceptable = 1;//标记接受
}
} else {
if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt,
pcb->rcv_nxt+pcb->rcv_wnd)) {//判断序列号是否相等
acceptable = 1;//标记接受
}
}
if (acceptable) {//接受了?
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n"));
LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED);
recv_flags |= TF_RESET;//连接复位标志
pcb->flags &= ~TF_ACK_DELAY;//延迟应答
return ERR_RST;//返回复位错误
} else {
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",
seqno, pcb->rcv_nxt));
LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",
seqno, pcb->rcv_nxt));
return ERR_OK;//返回OK
}
}
if ((flags & TCP_SYN) && (pcb->state != SYN_SENT && pcb->state != SYN_RCVD)) {
/* Cope with new connection attempt after remote end crashed */
/* 在远端崩溃后处理新的连接尝试 */
tcp_ack_now(pcb);//发送应答包
return ERR_OK;
}
/* Update the PCB (in)activity timer. */
/* 在激活计时器更新PCB. */
pcb->tmr = tcp_ticks;
pcb->keep_cnt_sent = 0;//Keep alive 计数器
tcp_parseopt(pcb);//分析传入的pcb选项
/* Do different things depending on the TCP state. */
/* 依据TCP状态做做不同的事情. */
switch (pcb->state) {
case SYN_SENT://同步发送状态
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno,
pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno)));
/* received SYN ACK with expected sequence number? */
/* 接收的SYN ACK是我们期待的序列号? */
if ((flags & TCP_ACK) && (flags & TCP_SYN)
&& ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) {
pcb->snd_buf++;//发送的可用buffer空间加1
pcb->rcv_nxt = seqno + 1;//下一个期待的接收序列号加1
pcb->rcv_ann_right_edge = pcb->rcv_nxt;//发布正确的窗口边缘
pcb->lastack = ackno;//最高的应答序号
pcb->snd_wnd = tcphdr->wnd;//发送者窗口
pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update *//*初始化序列号-1强迫窗口更新 */
pcb->state = ESTABLISHED;//建立连接状态
#if TCP_CALCULATE_EFF_SEND_MSS
pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip));//有效的发送最大段大小
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
/* Set ssthresh again after changing pcb->mss (already set in tcp_connect
* but for the default value of pcb->mss) */
/* 在改变pcb->后(已经在tcp_connect里设置)再次设置阀门,但是对默认pcb->mss值 */
pcb->ssthresh = pcb->mss * 10;
pcb->cwnd = ((pcb->cwnd == 1) ? (pcb->mss * 2) : pcb->mss);//pcb避免拥挤
LWIP_ASSERT("pcb->snd_queuelen > 0", (pcb->snd_queuelen > 0));
--pcb->snd_queuelen;//可用的发送buffer空间减1
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen));
rseg = pcb->unacked;//pcb未应答
pcb->unacked = rseg->next;
/* If there's nothing left to acknowledge, stop the retransmit
timer, otherwise reset it to start again */
/* 如果没有东西应答,停止传送计时器,否则重置来开始 */
if(pcb->unacked == NULL)
pcb->rtime = -1;
else {
pcb->rtime = 0;
pcb->nrtx = 0;
}
tcp_seg_free(rseg);//释放rseg
/* Call the user specified function to call when sucessfully
* connected. */
/* 成功了就调用用户指定的函数. */
TCP_EVENT_CONNECTED(pcb, ERR_OK, err);
tcp_ack_now(pcb);//发送应答包
}
/* received ACK? possibly a half-open connection */
/* 接收应答?可能一半打开了连接 */
else if (flags & TCP_ACK) {
/* send a RST to bring the other side in a non-synchronized state. */
/* 发送一个RST来带另外的一边进入不同步状态. */
tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src),
tcphdr->dest, tcphdr->src);
}
break;
case SYN_RCVD:
if (flags & TCP_ACK) {
/* expected ACK number? */
/* 是期待ACK数目? */
if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) {
u16_t old_cwnd;
pcb->state = ESTABLISHED;//建立连接状态
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
#if LWIP_CALLBACK_API
LWIP_ASSERT("pcb->accept != NULL", pcb->accept != NULL);
#endif
/* Call the accept function. */
/* 调用accept函数. */
TCP_EVENT_ACCEPT(pcb, ERR_OK, err);
if (err != ERR_OK) {
/* If the accept function returns with an error, we abort
* the connection. */
/* 如果accept函数返回错误,我们就终止连接. */
tcp_abort(pcb);
return ERR_ABRT;
}
old_cwnd = pcb->cwnd;
/* If there was any data contained within this ACK,
* we'd better pass it on to the application as well. */
/* 如果有任何数据包含在这个ACK.我们最好也将它传到应用层 */
tcp_receive(pcb);
pcb->cwnd = ((old_cwnd == 1) ? (pcb->mss * 2) : pcb->mss);
if (recv_flags & TF_GOT_FIN) {//如果得到远程终止标志
tcp_ack_now(pcb);//发送应答包
pcb->state = CLOSE_WAIT;//进入关闭等待状态
}
}
/* incorrect ACK number */
/* 不正确的ACK数目 */
else {
/* send RST */
/* 发送RST */
tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src),
tcphdr->dest, tcphdr->src);
}
} else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) {
/* Looks like another copy of the SYN - retransmit our SYN-ACK */
/* 就像其它的同步复制重传同步应答 */
tcp_rexmit(pcb);
}
break;
case CLOSE_WAIT:
/* FALLTHROUGH */
/* 落空 */
case ESTABLISHED:
tcp_receive(pcb);//接收pcb
if (recv_flags & TF_GOT_FIN) { /* passive close */ /*被动关闭 */
tcp_ack_now(pcb);//发送应答数据
pcb->state = CLOSE_WAIT;// 进入等待关闭状态
}
break;
case FIN_WAIT_1:
tcp_receive(pcb);//接收pcb
if (recv_flags & TF_GOT_FIN) {//连接被远程关闭
if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {//下一个新的被发送的序列号
LWIP_DEBUGF(TCP_DEBUG,
("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
tcp_ack_now(pcb);//发送数据包
tcp_pcb_purge(pcb);//清理一个TCP 的PCB,移除任何buffer数据和释放内存的buffer.
TCP_RMV(&tcp_active_pcbs, pcb);//在激活的pcb列表中移除pcb
pcb->state = TIME_WAIT;//等等关闭状态
TCP_REG(&tcp_tw_pcbs, pcb);//注册入pcb等等列表
} else {
tcp_ack_now(pcb);//传送应答包
pcb->state = CLOSING;//正在关闭状态
}
} else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {
pcb->state = FIN_WAIT_2;//进入FIN_WAIT_2超时状态等等
}
break;
case FIN_WAIT_2:
tcp_receive(pcb);//接收数据包
if (recv_flags & TF_GOT_FIN) {//连接被远程关闭
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
tcp_ack_now(pcb);//发送tcp应答包
tcp_pcb_purge(pcb);//清理pcb
TCP_RMV(&tcp_active_pcbs, pcb);//在tcp激活列表中移除pcb
pcb->state = TIME_WAIT;//等待关闭
TCP_REG(&tcp_tw_pcbs, pcb);//注册等待关闭pcb到列表
}
break;
case CLOSING:
tcp_receive(pcb);//接收数据包
if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
tcp_pcb_purge(pcb)//清理pcb
TCP_RMV(&tcp_active_pcbs, pcb);//移除pcb
pcb->state = TIME_WAIT;//状态标志
TCP_REG(&tcp_tw_pcbs, pcb);
}
break;
case LAST_ACK:
tcp_receive(pcb);//接收pcb
if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
/* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */
/* 修复错误 #21699: 不在这里设置pcb状态为CLOSED 或者我们冒段泄露的风险*/
recv_flags |= TF_CLOSED;//设置连接成功关闭标志
}
break;
default:
break;
}
return ERR_OK;
}
/**
* Called by tcp_process. Checks if the given segment is an ACK for outstanding
* data, and if so frees the memory of the buffered data. Next, is places the
* segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment
* is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until
* i it has been removed from the buffer.
*
* If the incoming segment constitutes an ACK for a segment that was used for RTT
* estimation, the RTT is estimated here as well.
*
* Called from tcp_process().
*
* @return 1 if the incoming segment is the next in sequence, 0 if not
*/
/**
* 被tcp_process调用,检查是否赋值的段是一个显著的ACK数据,如果是这样就是否缓冲的数据.
* 其次,是把段放置在任何接收队列里面.
* 如果段被缓冲,pbuf被pbuf_ref作为引用导致它将不被释放直到它已经被从缓冲中移除
*
* 如果进来的段构成一个ACK
* 对一个被使用来做RTT的段
*
* 被tcp_process调用
*
*
* @返回1如果传入的段是下一个序列号,如果不是返回0
*/
static u8_t
tcp_receive(struct tcp_pcb *pcb)
{
struct tcp_seg *next;
#if TCP_QUEUE_OOSEQ
struct tcp_seg *prev, *cseg;
#endif
struct pbuf *p;
s32_t off;
s16_t m;
u32_t right_wnd_edge;
u16_t new_tot_len;
u8_t accepted_inseq = 0;
if (flags & TCP_ACK) {//是TCP 应答包标志?
right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2;//发送窗口 + 序列应答最后窗口更新
/* Update window. */
/* 更新窗口. */
if (TCP_SEQ_LT(pcb->snd_wl1, seqno) ||
(pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) ||
(pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) {
pcb->snd_wnd = tcphdr->wnd;//发送窗口
pcb->snd_wl1 = seqno;//发送窗口最后应答
pcb->snd_wl2 = ackno;//发送窗口最后应答
if (pcb->snd_wnd > 0 && pcb->persist_backoff > 0) {
pcb->persist_backoff = 0;//持续计时器退出
}
LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"U16_F"\n", pcb->snd_wnd));
#if TCP_WND_DEBUG
} else {
if (pcb->snd_wnd != tcphdr->wnd) {
LWIP_DEBUGF(TCP_WND_DEBUG,
("tcp_receive: no window update lastack %"U32_F" ackno %"
U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n",
pcb->lastack, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2));
}
#endif /* TCP_WND_DEBUG */
}
if (pcb->lastack == ackno) {//是最后的应答号?
pcb->acked = 0;//应答置0
if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge){
++pcb->dupacks;//
if (pcb->dupacks >= 3 && pcb->unacked != NULL) {
if (!(pcb->flags & TF_INFR)) {
/* This is fast retransmit. Retransmit the first unacked segment. */
/* 快速重传. 重传第一个未应答段. */
LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupacks %"U16_F" (%"U32_F"), fast retransmit %"U32_F"\n",
(u16_t)pcb->dupacks, pcb->lastack,
ntohl(pcb->unacked->tcphdr->seqno)));
tcp_rexmit(pcb);
/* Set ssthresh to max (FlightSize / 2, 2*SMSS) */
/* 把阀值设置到最大 (FlightSize / 2, 2*SMSS) */
/*pcb->ssthresh = LWIP_MAX((pcb->snd_max -
pcb->lastack) / 2,
2 * pcb->mss);*/
/* Set ssthresh to half of the minimum of the current cwnd and the advertised window */
/* 设置阀门到目前船体和广告窗体的最小值的一半 */
if (pcb->cwnd > pcb->snd_wnd)
pcb->ssthresh = pcb->snd_wnd / 2;
else
pcb->ssthresh = pcb->cwnd / 2;
/* The minimum value for ssthresh should be 2 MSS */
/* 最小值应该是阀值的2个MSS */
if (pcb->ssthresh < 2*pcb->mss) {
LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: The minimum value for ssthresh %"U16_F" should be min 2 mss %"U16_F"...\n", pcb->ssthresh, 2*pcb->mss));
pcb->ssthresh = 2*pcb->mss;
}
pcb->cwnd = pcb->ssthresh + 3 * pcb->mss;
pcb->flags |= TF_INFR;
} else {
/* Inflate the congestion window, but not if it means that
the value overflows. */
if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
pcb->cwnd += pcb->mss;
}
}
}
} else {
LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupack averted %"U32_F" %"U32_F"\n",
pcb->snd_wl2 + pcb->snd_wnd, right_wnd_edge));
}
} else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)){
/* We come here when the ACK acknowledges new data. */
/* 当ACK确认有新的数据,我们进入这里. */
/* Reset the "IN Fast Retransmit" flag, since we are no longer
in fast retransmit. Also reset the congestion window to the
slow start threshold. */
/* 重置快速重传标志,直到我们不在重传.也给慢开始临界值重置拥挤窗口 */
if (pcb->flags & TF_INFR) {
pcb->flags &= ~TF_INFR;
pcb->cwnd = pcb->ssthresh;
}
/* Reset the number of retransmissions. */
/* 重置重传数值. */
pcb->nrtx = 0;
/* Reset the retransmission time-out. */
/* 重置重传超时. */
pcb->rto = (pcb->sa >> 3) + pcb->sv;
/* Update the send buffer space. Diff between the two can never exceed 64K? */
/* 根性发送buffer空间.不同的2个不可以超出64K? */
pcb->acked = (u16_t)(ackno - pcb->lastack);
pcb->snd_buf += pcb->acked;
/* Reset the fast retransmit variables. */
/* 重置快速重传变量. */
pcb->dupacks = 0;
pcb->lastack = ackno;
/* Update the congestion control variables (cwnd and
ssthresh). */
/* 更新拥挤控制变量(cwnd 和ssthresh). */
if (pcb->state >= ESTABLISHED) {//标志状态为建立连接标志
if (pcb->cwnd < pcb->ssthresh) {
if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
pcb->cwnd += pcb->mss;
}
LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"U16_F"\n", pcb->cwnd));
} else {
u16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd);
if (new_cwnd > pcb->cwnd) {
pcb->cwnd = new_cwnd;
}
LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"U16_F"\n", pcb->cwnd));
}
}
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n",
ackno,
pcb->unacked != NULL?
ntohl(pcb->unacked->tcphdr->seqno): 0,
pcb->unacked != NULL?
ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0));
/* Remove segment from the unacknowledged list if the incoming
ACK acknowlegdes them. */
/* 如果传入的ACK应答他们就从未应答列表中移除段. */
while (pcb->unacked != NULL &&
TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) +
TCP_TCPLEN(pcb->unacked), ackno)) {
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unacked\n",
ntohl(pcb->unacked->tcphdr->seqno),
ntohl(pcb->unacked->tcphdr->seqno) +
TCP_TCPLEN(pcb->unacked)));
next = pcb->unacked;//
pcb->unacked = pcb->unacked->next;
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));
LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));
pcb->snd_queuelen -= pbuf_clen(next->p);//计算链表里面的pbufs数量
tcp_seg_free(next);//释放tcp段
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unacked)\n", (u16_t)pcb->snd_queuelen));
if (pcb->snd_queuelen != 0) {
LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL ||
pcb->unsent != NULL);
}
}
/* If there's nothing left to acknowledge, stop the retransmit
timer, otherwise reset it to start again */
/* 如果没有什么来做应答,停止重传的计时器,否则重置来再次开始 */
if(pcb->unacked == NULL)
pcb->rtime = -1;
else
pcb->rtime = 0;
pcb->polltmr = 0;
} else {
/* Fix bug bug #21582: out of sequence ACK, didn't really ack anything */
/* 修好的错误 #21582:超出序列的ACK,不是真的应答 */
pcb->acked = 0;
}
/* We go through the ->unsent list to see if any of the segments
on the list are acknowledged by the ACK. This may seem
strange since an "unsent" segment shouldn't be acked. The
rationale is that lwIP puts all outstanding segments on the
->unsent list after a retransmission, so these segments may
in fact have been sent once. */
/* 我们通过pcb的unsent列表看到是否所有在段列表里面的都是未应答的ACK.
这个可能看起来奇怪,因为一个"unsent"段不应该被应答.原理是LwIP在重
传后放入未解决的段在未发送列表.因此这些段可以在实际中已经被发送了一次
*/
while (pcb->unsent != NULL &&
TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) +
TCP_TCPLEN(pcb->unsent), pcb->snd_nxt)) {
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n",
ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) +
TCP_TCPLEN(pcb->unsent)));
next = pcb->unsent;//pcb未发送标志
pcb->unsent = pcb->unsent->next;//未发送的下一个
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));
LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));
pcb->snd_queuelen -= pbuf_clen(next->p);//链表中pbuf的个数//Count number of pbufs in a chain
tcp_seg_free(next);//释放段
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unsent)\n", (u16_t)pcb->snd_queuelen));
if (pcb->snd_queuelen != 0) {//发送序列长度
LWIP_ASSERT("tcp_receive: valid queue length",
pcb->unacked != NULL || pcb->unsent != NULL);
}
}
/* End of ACK for new data processing. */
/* 新数据处理结束应答. */
LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %"U32_F" rtseq %"U32_F" ackno %"U32_F"\n",
pcb->rttest, pcb->rtseq, ackno));
/* RTT estimation calculations. This is done by checking if the
incoming segment acknowledges the segment we use to take a
round-trip time measurement. */
/* RTT估计计算.这个是被检测来做的,如果传入的段应答,我们使用这个段来做往返时间的测量 */
if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) {
/* diff between this shouldn't exceed 32K since this are tcp timer ticks
and a round-trip shouldn't be that long... */
/* 这个不应该操作32K由于这个是tcp计时器滴答数 , 一个往返不应该这么久 ... */
m = (s16_t)(tcp_ticks - pcb->rttest);
LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %"U16_F" ticks (%"U16_F" msec).\n",
m, m * TCP_SLOW_INTERVAL));
/* This is taken directly from VJs original code in his paper */
/* 这个被直接从VJs源码带到这个文件 */
m = m - (pcb->sa >> 3);
pcb->sa += m;
if (m < 0) {
m = -m;
}
m = m - (pcb->sv >> 2);
pcb->sv += m;
pcb->rto = (pcb->sa >> 3) + pcb->sv;//
LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" milliseconds)\n",
pcb->rto, pcb->rto * TCP_SLOW_INTERVAL));
pcb->rttest = 0;
}
}
/* If the incoming segment contains data, we must process it
further. */
/* 如果传入的段包含了数据,我们必须快速处理. */
if (tcplen > 0) {
/* This code basically does three things:
+) If the incoming segment contains data that is the next
in-sequence data, this data is passed to the application. This
might involve trimming the first edge of the data. The rcv_nxt
variable and the advertised window are adjusted.
+) If the incoming segment has data that is above the next
sequence number expected (->rcv_nxt), the segment is placed on
the ->ooseq queue. This is done by finding the appropriate
place in the ->ooseq queue (which is ordered by sequence
number) and trim the segment in both ends if needed. An
immediate ACK is sent to indicate that we received an
out-of-sequence segment.
+) Finally, we check if the first segment on the ->ooseq queue
now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If
rcv_nxt > ooseq->seqno, we must trim the first edge of the
segment on ->ooseq before we adjust rcv_nxt. The data in the
segments that are now on sequence are chained onto the
incoming segment so that we only need to call the application
once.
*/
/* 这个代码基于3个东西:
+)如果传入段包含下一个序列号的数据,这个数据被传入应用层,
这可能包含裁剪的第一个边缘的数据.rcv_nxt变量和广告窗口被调整
+)如果传入段有数据高于预期的下一个序号(->rcv_nxt),段被放在
->ooseq 队列.这个将被执行在寻找合适的地方的-->ooseq队列
(这是个有序的号码),且如果需要则整理在2端的段.一个立即ACk被发送
来表明我们几首一个超出队列号的段.
+)最后,我们检查是否第一个段在 ->ooseq队列中是现在的序号.如果
rcv_nxt > ooseq->seqno,在我们调整rcv_nxt之前,我们必须整理2端第一个在 ->ooseq上的边缘段,
数据在段中,是现在的序列链表传入段,因此我们只需要调用一次应用层。
*/
/* First, we check if we must trim the first edge. We have to do
this if the sequence number of the incoming segment is less
than rcv_nxt, and the sequence number plus the length of the
segment is larger than rcv_nxt. */
/* 首先,我们检查是否我们必须整理第一个边缘.我们必须做这个如果传入段序列号
数少于rcv_nxt,且序列编号加段长度大于rcv_nxt. */
/* if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/
if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)){
/* Trimming the first edge is done by pushing the payload
pointer in the pbuf downwards. This is somewhat tricky since
we do not want to discard the full contents of the pbuf up to
the new starting point of the data since we have to keep the
TCP header which is present in the first pbuf in the chain.
What is done is really quite a nasty hack: the first pbuf in
the pbuf chain is pointed to by inseg.p. Since we need to be
able to deallocate the whole pbuf, we cannot change this
inseg.p pointer to point to any of the later pbufs in the
chain. Instead, we point the ->payload pointer in the first
pbuf to data in one of the later pbufs. We also set the
inseg.data pointer to point to the right place. This way, the
->p pointer will still point to the first pbuf, but the
->p->payload pointer will point to data in another pbuf.
After we are done with adjusting the pbuf pointers we must
adjust the ->data pointer in the seg and the segment
length.*/
/* 在pbuf负载指针向下压是整理第一个边缘段.这有点棘手*/
off = pcb->rcv_nxt - seqno;
p = inseg.p;
LWIP_ASSERT("inseg.p != NULL", inseg.p);
LWIP_ASSERT("insane offset!", (off < 0x7fff));
if (inseg.p->len < off) {
LWIP_ASSERT("pbuf too short!", (((s32_t)inseg.p->tot_len) >= off));
new_tot_len = (u16_t)(inseg.p->tot_len - off);
while (p->len < off) {
off -= p->len;
/* KJM following line changed (with addition of new_tot_len var)
to fix bug #9076
inseg.p->tot_len -= p->len; */
/* KJM下面行更改(除了new_tot_len 变量)解决bug #9076
inseg.p->tot_len -= p->len; */
p->tot_len = new_tot_len;
p->len = 0;
p = p->next;
}
if(pbuf_header(p, (s16_t)-off)) {
/* Do we need to cope with this failing? Assert for now */
/* 我们需要应对这个失败?断言*/
LWIP_ASSERT("pbuf_header failed", 0);
}
} else {
if(pbuf_header(inseg.p, (s16_t)-off)) {
/* Do we need to cope with this failing? Assert for now */
/* 我们需要应对这个失败? 断言 */
LWIP_ASSERT("pbuf_header failed", 0);
}
}
/* KJM following line changed to use p->payload rather than inseg->p->payload
to fix bug #9076 */
inseg.dataptr = p->payload;
inseg.len -= (u16_t)(pcb->rcv_nxt - seqno);
inseg.tcphdr->seqno = seqno = pcb->rcv_nxt;
}
else {
if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
/* the whole segment is < rcv_nxt */
/* must be a duplicate of a packet that has already been correctly handled */
/* 全部断都是小于 rcv_nxt */
/* 必须是一个已经正确使用的包*/
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", seqno));
tcp_ack_now(pcb);
}
}
/* The sequence number must be within the window (above rcv_nxt
and below rcv_nxt + rcv_wnd) in order to be further
processed. */
/* 序列号必须在窗口里面,为了在之后被处理. */
if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt,
pcb->rcv_nxt + pcb->rcv_wnd - 1)){
if (pcb->rcv_nxt == seqno) {
accepted_inseq = 1;
/* The incoming segment is the next in sequence. We check if
we have to trim the end of the segment and update rcv_nxt
and pass the data to the application. */
/* 传入的段是下一个在序列里面的.我们检查是否我们必须真理段的2端,更新rcv_nxt和传递数据到应用程序 */
tcplen = TCP_TCPLEN(&inseg);
if (tcplen > pcb->rcv_wnd) {
LWIP_DEBUGF(TCP_INPUT_DEBUG,
("tcp_receive: other end overran receive window"
"seqno %"U32_F" len %"U32_F" right edge %"U32_F"\n",
seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd));
if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
/* Must remove the FIN from the header as we're trimming
* that byte of sequence-space from the packet */
/* 必须从头部移除FIN作为我们整理包里的序号空间字节*/
TCPH_FLAGS_SET(inseg.tcphdr, TCPH_FLAGS(inseg.tcphdr) &~ TCP_FIN);
}
/* Adjust length of segment to fit in the window. */
/* 调整段的长度来是窗口合适. */
inseg.len = pcb->rcv_wnd;
if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) {
inseg.len -= 1;
}
pbuf_realloc(inseg.p, inseg.len);
tcplen = TCP_TCPLEN(&inseg);
LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n",
(seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd));
}
#if TCP_QUEUE_OOSEQ
if (pcb->ooseq != NULL) {
if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
LWIP_DEBUGF(TCP_INPUT_DEBUG,
("tcp_receive: received in-order FIN, binning ooseq queue\n"));
/* Received in-order FIN means anything that was received
* out of order must now have been received in-order, so
* bin the ooseq queue */
/* 接收有序的FIN意味着,所有的被无需接收现在必须被有序接收 */
while (pcb->ooseq != NULL) {
struct tcp_seg *old_ooseq = pcb->ooseq;
pcb->ooseq = pcb->ooseq->next;
memp_free(MEMP_TCP_SEG, old_ooseq);
}
} else if (TCP_SEQ_LEQ(pcb->ooseq->tcphdr->seqno, seqno + tcplen)) {
if (pcb->ooseq->len > 0) {
/* We have to trim the second edge of the incoming segment. */
/* 我们必须整理传入段的第二个边缘. */
LWIP_ASSERT("tcp_receive: trimmed segment would have zero length\n",
TCP_SEQ_GT(pcb->ooseq->tcphdr->seqno, seqno));
/* FIN in inseg already handled by dropping whole ooseq queue */
/* FIN 在inseg中已经被退出所有ooseq队列掌控了 */
inseg.len = (u16_t)(pcb->ooseq->tcphdr->seqno - seqno);
if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) {
inseg.len -= 1;
}
pbuf_realloc(inseg.p, inseg.len);//缩小链的长度
tcplen = TCP_TCPLEN(&inseg);//TCP长度
LWIP_ASSERT("tcp_receive: segment not trimmed correctly to ooseq queue\n",
(seqno + tcplen) == pcb->ooseq->tcphdr->seqno);
} else {
/* does the ooseq segment contain only flags that are in inseg also? */
/* ooseq段值包含flag,inseg里面也这样? */
if ((TCPH_FLAGS(inseg.tcphdr) & (TCP_FIN|TCP_SYN)) ==
(TCPH_FLAGS(pcb->ooseq->tcphdr) & (TCP_FIN|TCP_SYN))) {
struct tcp_seg *old_ooseq = pcb->ooseq;
pcb->ooseq = pcb->ooseq->next;
memp_free(MEMP_TCP_SEG, old_ooseq);//释放buffer
}
}
}
}
#endif /* TCP_QUEUE_OOSEQ */
pcb->rcv_nxt = seqno + tcplen;
/* Update the receiver's (our) window. */
/* 更新接收端的(我们的)窗口. */
LWIP_ASSERT("tcp_receive: tcplen > rcv_wnd\n", pcb->rcv_wnd >= tcplen);
pcb->rcv_wnd -= tcplen;//减去tcp长度
tcp_update_rcv_ann_wnd(pcb);//更新发布窗口
/* If there is data in the segment, we make preparations to
pass this up to the application. The ->recv_data variable
is used for holding the pbuf that goes to the
application. The code for reassembling out-of-sequence data
chains its data on this pbuf as well.
If the segment was a FIN, we set the TF_GOT_FIN flag that will
be used to indicate to the application that the remote side has
closed its end of the connection. */
/* 如果有数据在段里面,我们准备把这些数据传到上层应用.->recv_data 变量被使用来
支持pbuf传到上层应用.重新装配的超出队列的数据量数据链代码它在pbuf的数据也一样.
如果段是一个FIN,我们设置TF_GOT_FIN标志将被使用来指明应用层远端已经关闭它的连接终端
*/
if (inseg.p->tot_len > 0) {
recv_data = inseg.p;
/* Since this pbuf now is the responsibility of the
application, we delete our reference to it so that we won't
(mistakingly) deallocate it. */
/* 因为这个pbuf现在是应用程序负责的.我们删除我们对它的引用将导致我们不能(错误地)释放它 */
inseg.p = NULL;
}
if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n"));
recv_flags |= TF_GOT_FIN;
}
#if TCP_QUEUE_OOSEQ
/* We now check if we have segments on the ->ooseq queue that
is now in sequence. */
/* 我们现在检查是否我们有段在->ooseq现在的序列号队列里面. */
while (pcb->ooseq != NULL &&
pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) {
cseg = pcb->ooseq;
seqno = pcb->ooseq->tcphdr->seqno;
pcb->rcv_nxt += TCP_TCPLEN(cseg);
LWIP_ASSERT("tcp_receive: ooseq tcplen > rcv_wnd\n",
pcb->rcv_wnd >= TCP_TCPLEN(cseg));
pcb->rcv_wnd -= TCP_TCPLEN(cseg);
tcp_update_rcv_ann_wnd(pcb);
if (cseg->p->tot_len > 0) {
/* Chain this pbuf onto the pbuf that we will pass to
the application. */
/* 用链串这个pbuf到我们要传出的应用程序的pbuf中 . */
if (recv_data) {
pbuf_cat(recv_data, cseg->p);
} else {
recv_data = cseg->p;
}
cseg->p = NULL;
}
if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n"));
recv_flags |= TF_GOT_FIN;
if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */
/* 强制被动关闭或者我们可以移动到激活关闭 */
pcb->state = CLOSE_WAIT;
}
}
pcb->ooseq = cseg->next;
tcp_seg_free(cseg);
}
#endif /* TCP_QUEUE_OOSEQ */
/* Acknowledge the segment(s). */
/* 确认段. */
tcp_ack(pcb);
} else {
/* We get here if the incoming segment is out-of-sequence. */
/* 我们到这里如果传入段是超出序列号的段. */
tcp_ack_now(pcb);
#if TCP_QUEUE_OOSEQ
/* We queue the segment on the ->ooseq queue. */
/* 我们排队段在->ooseq 队列里. */
if (pcb->ooseq == NULL) {
pcb->ooseq = tcp_seg_copy(&inseg);
} else {
/* If the queue is not empty, we walk through the queue and
try to find a place where the sequence number of the
incoming segment is between the sequence numbers of the
previous and the next segment on the ->ooseq queue. That is
the place where we put the incoming segment. If needed, we
trim the second edges of the previous and the incoming
segment so that it will fit into the sequence.
If the incoming segment has the same sequence number as a
segment on the ->ooseq queue, we discard the segment that
contains less data. */
/* 如果队列不是空的,我们走遍队列而且尝试找出一块地方在序列号传入段
之前的序列号和序列号传入段在->ooseq队列的下一个段之间.这是我们放入传
入段的地方,如果需要,我们整理第二个之前的边缘和传入段,
因此将适应到序列里面.
如果传入的段有相同的序列号作为一个在->ooseq队列的段,我们抛弃包含很少数据的段.
*/
prev = NULL;
for(next = pcb->ooseq; next != NULL; next = next->next) {
if (seqno == next->tcphdr->seqno) {
/* The sequence number of the incoming segment is the
same as the sequence number of the segment on
->ooseq. We check the lengths to see which one to
discard. */
/* 传入段序列号和->ooseq段中的序列号相同,我们检测长度来看哪个要被抛弃. */
if (inseg.len > next->len) {
/* The incoming segment is larger than the old
segment. We replace the old segment with the new
one. */
/* 传入的段比旧的段大,我们用新段替代旧的段. */
cseg = tcp_seg_copy(&inseg);
if (cseg != NULL) {
cseg->next = next->next;
if (prev != NULL) {
prev->next = cseg;
} else {
pcb->ooseq = cseg;
}
tcp_seg_free(next);
if (cseg->next != NULL) {
next = cseg->next;
if (TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) {
/* We need to trim the incoming segment. */
/* 我们需要整理传入的段. */
cseg->len = (u16_t)(next->tcphdr->seqno - seqno);
pbuf_realloc(cseg->p, cseg->len);
}
}
}
break;
} else {
/* Either the lenghts are the same or the incoming
segment was smaller than the old one; in either
case, we ditch the incoming segment. */
/* 是否长度是传入的段长度一样或者传入长度比旧的小;其他情况,我们丢弃传入段. */
break;
}
} else {
if (prev == NULL) {
if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {
/* The sequence number of the incoming segment is lower
than the sequence number of the first segment on the
queue. We put the incoming segment first on the
queue. */
/* 传入段的序列号比第一个在队列里的段序列号小.我们把传入段作为队列的第一个 */
if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) {
/* We need to trim the incoming segment. */
/* 我们需要整理传入段. */
inseg.len = (u16_t)(next->tcphdr->seqno - seqno);
pbuf_realloc(inseg.p, inseg.len);
}
cseg = tcp_seg_copy(&inseg);
if (cseg != NULL) {
cseg->next = next;
pcb->ooseq = cseg;
}
break;
}
} else
/*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) &&
TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/
if(TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)){
/* The sequence number of the incoming segment is in
between the sequence numbers of the previous and
the next segment on ->ooseq. We trim and insert the
incoming segment and trim the previous segment, if
needed. */
/* 传入段序列号在前一个序列号和后一个段->ooseq的序列号之间.假如需要我们整理、插入传入段和整理前一个段 */
if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) {
/* We need to trim the incoming segment. */
/* 我们需要整理传入段. */
inseg.len = (u16_t)(next->tcphdr->seqno - seqno);
pbuf_realloc(inseg.p, inseg.len);
}
cseg = tcp_seg_copy(&inseg);
if (cseg != NULL) {
cseg->next = next;
prev->next = cseg;
if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) {
/* We need to trim the prev segment. */
/* 我们需要整理前一个段. */
prev->len = (u16_t)(seqno - prev->tcphdr->seqno);
pbuf_realloc(prev->p, prev->len);
}
}
break;
}
/* If the "next" segment is the last segment on the
ooseq queue, we add the incoming segment to the end
of the list. */
/* 如果"下一个"段是最后一个在ooseq队列里的段,我们增加一个传入段到列表最后. */
if (next->next == NULL &&
TCP_SEQ_GT(seqno, next->tcphdr->seqno)) {
next->next = tcp_seg_copy(&inseg);
if (next->next != NULL) {
if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) {
/* We need to trim the last segment. */
/* 我们需要整理最后的段. */
next->len = (u16_t)(seqno - next->tcphdr->seqno);
pbuf_realloc(next->p, next->len);
}
}
break;
}
}
prev = next;
}
}
#endif /* TCP_QUEUE_OOSEQ */
}
} else {
tcp_ack_now(pcb);
}
} else {
/* Segments with length 0 is taken care of here. Segments that
fall out of the window are ACKed. */
/* 长度为0的段在这里要注意了. 放弃窗口的段是被应答了的*/
/*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) ||
TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/
if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){
tcp_ack_now(pcb);
}
}
return accepted_inseq;
}
/**
* Parses the options contained in the incoming segment.
*
* Called from tcp_listen_input() and tcp_process().
* Currently, only the MSS option is supported!
*
* @param pcb the tcp_pcb for which a segment arrived
*/
/**
* 分析传入段包含的选项
*
* 被tcp_listen_input() 和 tcp_process()调用
* 目前,只是MSS选项被支持
*
* @参数pcb:一个段到达的tcp_pcb
*/
static void
tcp_parseopt(struct tcp_pcb *pcb)
{
u16_t c, max_c;
u16_t mss;
u8_t *opts, opt;
#if LWIP_TCP_TIMESTAMPS
u32_t tsval;
#endif
opts = (u8_t *)tcphdr + TCP_HLEN;
/* Parse the TCP MSS option, if present. */
/* 如果存在,则分析TCP最大段大小选项. */
if(TCPH_HDRLEN(tcphdr) > 0x5) {
max_c = (TCPH_HDRLEN(tcphdr) - 5) << 2;
for (c = 0; c < max_c; ) {
opt = opts[c];//选项
switch (opt) {
case 0x00:
/* End of options. */
/* 选项结束. */
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: EOL\n"));
return;
case 0x01:
/* NOP option. */
/* 空选项. */
++c;
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: NOP\n"));
break;
case 0x02:
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: MSS\n"));
if (opts[c + 1] != 0x04 || c + 0x04 > max_c) {
/* Bad length */
/* 坏长度 */
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
return;
}
/* An MSS option with the right option length. */
/* 一个MSS选项后天对的选项长度. */
mss = (opts[c + 2] << 8) | opts[c + 3];
/* Limit the mss to the configured TCP_MSS and prevent division by zero */
/* 对TCP_MSS配置做限制 和防止被0整除*/
pcb->mss = ((mss > TCP_MSS) || (mss == 0)) ? TCP_MSS : mss;
/* Advance to next option */
c += 0x04;
break;
#if LWIP_TCP_TIMESTAMPS
case 0x08:
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: TS\n"));
if (opts[c + 1] != 0x0A || c + 0x0A > max_c) {
/* Bad length */
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
return;
}
/* TCP timestamp option with valid length */
tsval = (opts[c+2]) | (opts[c+3] << 8) |
(opts[c+4] << 16) | (opts[c+5] << 24);
if (flags & TCP_SYN) {
pcb->ts_recent = ntohl(tsval);
pcb->flags |= TF_TIMESTAMP;
} else if (TCP_SEQ_BETWEEN(pcb->ts_lastacksent, seqno, seqno+tcplen)) {
pcb->ts_recent = ntohl(tsval);
}
/* Advance to next option */
c += 0x0A;
break;
#endif
default:
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: other\n"));
if (opts[c + 1] == 0) {
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
/* If the length field is zero, the options are malformed
and we don't process them further. */
/* 如果长度区域为0,选项是畸形的,我们对这些不做跟远的处理. */
return;
}
/* All other options have a length field, so that we easily
can skip past them. */
/* 所有的选项有一个长度区域,所以我们容易跳过它. */
c += opts[c + 1];
}
}
}
}
#endif /* LWIP_TCP */