您的位置:首页 > 理论基础 > 计算机网络

linux网络协议栈分析(五)

2010-07-29 08:48 447 查看
/*#######################################
*
*author Andy Yixin Deng
*Nankai University
*email: andy.yx.deng@gmail.com
*
/*#######################################
本贴为原创,如转载请标明出处!

上回写到了linux发送syn请求的过程,今天以及侦听端收到了syn请求的处理,今天我们写一写连接端收到syn——ack的处理和侦听端口收到了ack的处理过程。

首先开tcp_rcv这个函数中的这样一段代码

这段代码是针对本端是tcp-syn-sent的状态写的。

if(sk->state==TCP_SYN_SENT)

{

/* Crossed SYN or previous junk segment */

if(th->ack)

{

/* We got an ack, but it's not a good ack */

if(!tcp_ack(sk,th,saddr,len))

{

/* Reset the ack - its an ack from a

different connection [ th->rst is checked in tcp_reset()] */

tcp_statistics.TcpAttemptFails++;

tcp_reset(daddr, saddr, th,

sk->prot, opt,dev,sk->ip_tos,sk->ip_ttl);

kfree_skb(skb, FREE_READ);

release_sock(sk);

return(0);

}

if(th->rst)

return tcp_std_reset(sk,skb);

if(!th->syn)

{

/* A valid ack from a different connection

start. Shouldn't happen but cover it */

kfree_skb(skb, FREE_READ);

release_sock(sk);

return 0;

}

/*

* Ok.. it's good. Set up sequence numbers and

* move to established.

*/

syn_ok=1; /* Don't reset this connection for the syn */

sk->acked_seq=th->seq+1;

sk->fin_seq=th->seq;

tcp_send_ack(sk->sent_seq,sk->acked_seq,sk,th,sk->daddr);

tcp_set_state(sk, TCP_ESTABLISHED);//状态变为了建立状态!

tcp_options(sk,th);

sk->dummy_th.dest=th->source;

sk->copied_seq = sk->acked_seq;

if(!sk->dead)

{

sk->state_change(sk);//唤醒睡眠等待的进程

sock_wake_async(sk->socket, 0);

}

if(sk->max_window==0)

{

sk->max_window = 32;

sk->mss = min(sk->max_window, sk->mtu);

}

}

else

{

//如果走进了这个分支说明这个报文是个单纯的syn报文,也就是两段同时建立连接

/* See if SYN's cross. Drop if boring */

if(th->syn && !th->rst)

{

/* Crossed SYN's are fine - but talking to

yourself is right out... */

if(sk->saddr==saddr && sk->daddr==daddr &&

sk->dummy_th.source==th->source &&

sk->dummy_th.dest==th->dest)

{

tcp_statistics.TcpAttemptFails++;

return tcp_std_reset(sk,skb);

}

tcp_set_state(sk,TCP_SYN_RECV);

/*

* FIXME:

* Must send SYN|ACK here

*/

}

/* Discard junk segment */

kfree_skb(skb, FREE_READ);

release_sock(sk);

return 0;

}

/*

* SYN_RECV with data maybe.. drop through

*/

goto rfc_step6;

}

对于tcp-syn-sent状态的socket连接它有两种状态的改变分支
一个分支就是收到了syn-ack,也就是连接建立成功,
一种分支是收到了单纯的syn报文,状态将转移到tcp-syn-recv状态去。
那么上面的分析主要是针对的连接发起方收到了侦听方的两种可能报文的处理,这样我们只要分析连接侦听方收到了ack回应后的处理就可以了
看tcp_rcv这个函数中的一个代码片段

if(th->ack && !tcp_ack(sk,th,saddr,len))
{
/*
* Our three way handshake failed.
*/

if(sk->state==TCP_SYN_RECV)
{
tcp_reset(daddr, saddr, th,sk->prot, opt, dev,sk->ip_tos,sk->ip_ttl);
}
kfree_skb(skb, FREE_READ);
release_sock(sk);
return 0;
}

在tcp_ack这个函数中,如果socket的状态是syn-rcv状态的,则将状态转变为tcp-established状态就可以了唤醒睡眠的进程。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: