Table of Contents
tcp_done
void tcp_done(struct sock *sk)
{
struct request_sock *req = tcp_sk(sk)->fastopen_rsk;
if (sk->sk_state == TCP_SYN_SENT || sk->sk_state == TCP_SYN_RECV)
TCP_INC_STATS(sock_net(sk), TCP_MIB_ATTEMPTFAILS);
tcp_set_state(sk, TCP_CLOSE);
tcp_clear_xmit_timers(sk);
if (req)
reqsk_fastopen_remove(sk, req, false);
sk->sk_shutdown = SHUTDOWN_MASK;
if (!sock_flag(sk, SOCK_DEAD))
sk->sk_state_change(sk);
else
inet_csk_destroy_sock(sk);
}
- 设置状态为TCP_CLOSE;
- 清理相关timer:pacing,compressed ack,以及其他delay,重传之类的timer;
- 清理fastopen相关的request_sock; 4.设置
sk_shutdown
为SHUTDOWN_MASK
; 5.如果这个sk没有被标记SOCK_DEAD
,那么调用sk_state_change
处理这个sk,否则调用inet_csk_destroy_sock
处理;sk_state_change
是sock
初始化的时候在sock_init_data
中设置的,默认值为sock_def_wakeup
。 这个sk_state_change
是struct sock
这个基类里初始化的一个函数,大致就是epoll事件的回调的意思,sk_state_change
被赋值为sock_def_wakeup
用来唤醒应用进程,告知其此socket状态已经改变。
inet_csk_destroy_sock
那么继续理解inet_csk_destroy_sock
的逻辑:
void inet_csk_destroy_sock(struct sock *sk)
{
WARN_ON(sk->sk_state != TCP_CLOSE);
WARN_ON(!sock_flag(sk, SOCK_DEAD));
/* It cannot be in hash table! */
WARN_ON(!sk_unhashed(sk));
/* If it has not 0 inet_sk(sk)->inet_num, it must be bound */
WARN_ON(inet_sk(sk)->inet_num && !inet_csk(sk)->icsk_bind_hash);
sk->sk_prot->destroy(sk);
sk_stream_kill_queues(sk);
xfrm_sk_free_policy(sk);
sk_refcnt_debug_release(sk);
percpu_counter_dec(sk->sk_prot->orphan_count);
sock_put(sk);
}
从这个实现可以看出,到tcp_done
的时候,这个TCP socket必须早已经从hash_info中给删除掉了。
调用tcp_done的时机
- 在
tcp_abort
中调用,而tcp_abort
是用来赋值给sock_diag的diag_destroy指针的;
但是这个tcp_abort函数应该是有bug的,只能用来作为参考; - 在
tcp_reset
中调用;
这是在收到RSET包后调用的; - 在
tcp_rcv_state_process
中调用;
TCP在收到包后会调用tcp_rcv_state_process
进行处理,具体逻辑暂时不管,从中可以看到处于LAST_ACK的socket在收到正确的包后会直接调用tcp_done结束自己; - 在
tcp_v4_err
中调用; - 在
tcp_v4_syn_recv_sock
中调用; - 在
tcp_time_wait
中调用;
在TCP socket要进入time-wait或者fin-wait-2状态时,会调用tcp_time_wait
函数,创建一个新的inet_timewait_sock来取代原来的sock,并且将原来的sock释放掉以节约内存; - 在
tcp_write_err
中调用; - 在
tcp_out_of_resources
中调用; - 在
tcp_keepalive_timer
中调用; - 在
tcp_v6_err
中调用; - 在
tcp_v6_syn_recv_sock
中调用;
tcp_send_active_reset
释放congestion control的时机
在tcp_cleanup_congestion_control中会调用congestion control注册的destroy函数。
tcp_reinit_congestion_control
切换cc算法时调用;tcp_v4_destroy_sock
调用;
那么什么时候会调用这个tcp_v4_destroy_sock
呢?
tcp_v6_destroy_sock
里会调用,有点类似tcp_ipv6是tcp_ipv4的子类的意思;tcp_v4_destroy_sock
注册成了tcp_ipv4的destroy
函数;
那么什么时候会调用这个注册的destroy函数呢?
inet_csk_destroy_sock
函数调用;
嗯,可以把tcp_sock看作inet_connection_sock的子类吧。tcp_done
里可能会调用inet_csk_destroy_sock
,也就是说tcp_done
函数里大概率就把tcp socket关联的congestion control给释放掉了。sk_common_release
中调用;
近期评论