注册 登录  
 加关注
查看详情
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

蒙奇D小豌豆的博客

蒙奇D小豌豆的学习记录

 
 
 

日志

 
 

Tcp in kernel connection termination  

2014-07-01 16:30:09|  分类: network |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
1. A send fin with close/shutdown write
int inet_release(struct socket *sock)
{
timeout = 0;
/*if socketset SOCK_LINGER get the timeout*/
if (sock_flag(sk, SOCK_LINGER) &&
   !(current->flags & PF_EXITING))
timeout = sk->sk_lingertime;
sock->sk = NULL;
sk->sk_prot->close(sk, timeout);//tcp_close
}

void tcp_close(struct sock *sk, long timeout)
{
//mask all read and write
sk->sk_shutdown = SHUTDOWN_MASK;

//server one just close all the half open connection and connection in accept queue
if (sk->sk_state == TCP_LISTEN) {
tcp_set_state(sk, TCP_CLOSE);

/* Special case. */
inet_csk_listen_stop(sk);

goto adjudge_to_death;
}

/*free all the unread data in the recieve queue*/
while ((skb = __skb_dequeue(&sk->sk_receive_queue)) != NULL) {
data_was_unread += len;
__kfree_skb(skb);
}

if (data_was_unread) {
/*if there are unread data, send rst to peer directly*/
tcp_set_state(sk, TCP_CLOSE);
tcp_send_active_reset(sk, sk->sk_allocation);
} else if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) {
/* if the sock set SOCK_LINGER and the lingertime is zero, it also sends rst to peer */
sk->sk_prot->disconnect(sk, 0);
} else if (tcp_close_state(sk)) {//set sk state to anther state and check if it need send a fin
/*in this case we need send fin and change state from established to fin_wait1*/
/*send fin*/
tcp_send_fin(sk);
}

/*wait depend on timeout, nomally is zero*/
/*it will be waked up by timeout or receive the ack of the fin*/
sk_stream_wait_close(sk, timeout);

/*set the sock to DEATH unlink socket and sock*/
sock_orphan(sk);
//sock_set_flag(sk, SOCK_DEAD);
//sk_set_socket(sk, NULL);
//sk->sk_wq  = NULL

/* It is the last release_sock in its life. It will remove backlog. */
release_sock(sk);

/*if we get the ack of the fin after timeout*/
if (sk->sk_state == TCP_FIN_WAIT2) {
struct tcp_sock *tp = tcp_sk(sk);
/*TCP_LINGER2 set the timeout of the tcp sk in TIME_WAIT state.
if the value is less than zero the tcp sk can't gey in TIME_WAIT state
then send the rst to peer*/
if (tp->linger2 < 0) {
tcp_set_state(sk, TCP_CLOSE);
tcp_send_active_reset(sk, GFP_ATOMIC);
} else {
/*get timeout according tcp_fin_timeout, tp->linger2 and 3.5rto*/
const int tmo = tcp_fin_time(sk);

if (tmo > TCP_TIMEWAIT_LEN) {
inet_csk_reset_keepalive_timer(sk,
tmo - TCP_TIMEWAIT_LEN);
} else {
/*go to the fake time_wait state*/
tcp_time_wait(sk, TCP_FIN_WAIT2, tmo);
goto out;
}
}
}
}

static const unsigned char new_state[16] = {
  /* current state:        new state:      action: */
  /* (Invalid) */ TCP_CLOSE,
  /* TCP_ESTABLISHED */ TCP_FIN_WAIT1 | TCP_ACTION_FIN,
  /* TCP_SYN_SENT */ TCP_CLOSE,
  /* TCP_SYN_RECV */ TCP_FIN_WAIT1 | TCP_ACTION_FIN,
  /* TCP_FIN_WAIT1 */ TCP_FIN_WAIT1,
  /* TCP_FIN_WAIT2 */ TCP_FIN_WAIT2,
  /* TCP_TIME_WAIT */ TCP_CLOSE,
  /* TCP_CLOSE */ TCP_CLOSE,
  /* TCP_CLOSE_WAIT */ TCP_LAST_ACK  | TCP_ACTION_FIN,
  /* TCP_LAST_ACK */ TCP_LAST_ACK,
  /* TCP_LISTEN */ TCP_CLOSE,
  /* TCP_CLOSING */ TCP_CLOSING,
};

static int tcp_close_state(struct sock *sk)
{
int next = (int)new_state[sk->sk_state];
int ns = next & TCP_STATE_MASK;

tcp_set_state(sk, ns);

return next & TCP_ACTION_FIN;
}


2. B receive the fin and send ack
tcp_v4_rcv--->tcp_v4_do_rcv
{
/*B is still in ESTABLISHED state*/
if (sk->sk_state == TCP_ESTABLISHED) {
tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len);
}
}

tcp_rcv_established--->tcp_data_queue
{
/*recv fin*/
tcp_data_queue()
//if (th->fin)
//tcp_fin(sk);

/*send ack*/
tcp_ack_snd_check(sk);
}

void tcp_fin(struct sock *sk)
{
sk->sk_shutdown |= RCV_SHUTDOWN;

switch (sk->sk_state) {
case TCP_SYN_RECV:
case TCP_ESTABLISHED:
/* Move to CLOSE_WAIT */
tcp_set_state(sk, TCP_CLOSE_WAIT);
break;
.......
}

3. A receive the ack
tcp_v4_rcv--->tcp_v4_do_rcv--->tcp_rcv_state_process
{
if (!th->ack && !th->rst)
goto discard;

/* step 5: check the ACK field */
acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH |
     FLAG_UPDATE_TS_RECENT) > 0;

switch (sk->sk_state) {
case TCP_FIN_WAIT1: {
tcp_set_state(sk, TCP_FIN_WAIT2);
sk->sk_shutdown |= SEND_SHUTDOWN;

if (!sock_flag(sk, SOCK_DEAD)) {
/* Wake up lingering close() */
sk->sk_state_change(sk);
break;
}
/*directly into the close state if tcp_linger2 is less than zero*/
if (tp->linger2 < 0) {
tcp_done(sk)
//tcp_set_state(sk, TCP_CLOSE);
} else {
/*get timeout according the max of tcp_fin_timeout, tp->linger2 and 3.5rto*/
const int tmo = tcp_fin_time(sk);

if (tmo > TCP_TIMEWAIT_LEN) {
inet_csk_reset_keepalive_timer(sk,
tmo - TCP_TIMEWAIT_LEN);
} else {
/*go to the fake time_wait state*/
tcp_time_wait(sk, TCP_FIN_WAIT2, tmo);
goto out;
}
}
}
}
}


4. B send the fin
inet_release-->tcp_close(): is the same same setp1 except belows
{
....
else if (tcp_close_state(sk)) {//set sk state to anther state and check if it need send a fin
/*in this case we need send fin and change state from close_wait to last_ack*/
/*send fin*/
tcp_send_fin(sk);
}
....
}

5. A receive the fin and send the last ack
tcp_v4_rcv--->tcp_v4_do_rcv--->tcp_rcv_state_process
{
case TCP_FIN_WAIT2:
tcp_data_queue()-->tcp_fin()
}

int tcp_fin()
{
case TCP_FIN_WAIT2:
/* Received a FIN -- send ACK and enter TIME_WAIT. */
tcp_send_ack(sk);
tcp_time_wait(sk, TCP_TIME_WAIT, 0);
}


6. B recieve the last ack
tcp_v4_rcv--->tcp_v4_do_rcv--->tcp_rcv_state_process
{
case TCP_LAST_ACK:
if (tp->snd_una == tp->write_seq) {
tcp_update_metrics(sk);
/*set the tcp state to close*/
tcp_done(sk);
goto discard;
}
}


  评论这张
 
阅读(179)| 评论(0)

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018