这篇笔记记录connect()系统调用的后半部分,即客户端收到SYN+ACK响应,然后回复ACK的部分。
1. 客户端收到SYN+ACK报文
发送SYN请求报文后,TCB的状态由TCP_CLOSE迁移到TCP_SYN_SENT,所以在收到接收响应后,将由tcp_rcv_state_process()处理。
1.1 tcp_rcv_state_process()
/*
* This function implements the receiving procedure of RFC 793 for
* all states except ESTABLISHED and TIME_WAIT.
* It's called from both tcp_v4_rcv and tcp_v6_rcv and should be
* address independent.
*/
int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
struct tcphdr *th, unsigned len)
{
struct tcp_sock *tp = tcp_sk(sk);
struct inet_connection_sock *icsk = inet_csk(sk);
int queued = 0;
tp->rx_opt.saw_tstamp = 0;
switch (sk->sk_state) {
...
case TCP_SYN_SENT:
//由tcp_rcv_synsent_state_process()处理输入报文
queued = tcp_rcv_synsent_state_process(sk, skb, th, len);
//返回值大于0表示处理失败,这会导致调用者向服务器端发送RST报文
if (queued >= 0)
return queued;
/* Do step6 onward by hand. */
//处理紧急数据
tcp_urg(sk, skb, th);
__kfree_skb(skb);
//检测是否有数据要发送,对于客户端,三次握手完成,可以继续发送数据
tcp_data_snd_check(sk);
return 0;
}
}
1.2 SYN_SENT状态输入报文处理
@返回1:发送复位报文;
@返回0:处理正常,停止对数据包的后续处理;
@返回-1:处理正常,继续处理紧急数据,并且尝试触发发送逻辑
static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
struct tcphdr *th, unsigned len)
{
struct tcp_sock *tp = tcp_sk(sk);
struct inet_connection_sock *icsk = inet_csk(sk);
int saved_clamp = tp->rx_opt.mss_clamp;
//解析TCP选项
tcp_parse_options(skb, &tp->rx_opt, 0);
//报文中携带了ACK标记
if (th->ack) {
/* rfc793:
* "If the state is SYN-SENT then
* first check the ACK bit
* If the ACK bit is set
* If SEG.ACK =< ISS, or SEG.ACK > SND.NXT, send
* a reset (unless the RST bit is set, if so drop
* the segment and return)"
*
* We do not send data with SYN, so that RFC-correct
* test reduces to:
*/
//输入报文不是对SYN报文的确认,会向对端发送RST报文
if (TCP_SKB_CB(skb)->ack_seq != tp->snd_nxt)