TCP层close系统调用的实现分析

在调用close系统调用关闭套接字时,如果套接字引用计数已经归零,则需继续向上层调用其close实现,tcp为tcp_close;本文仅介绍tcp部分,前置部分请参考本博关于close系统调用的文章;

  1 void tcp_close(struct sock *sk, long timeout)
  2 {
  3     struct sk_buff *skb;
  4     int data_was_unread = 0;
  5     int state;
  6 
  7     lock_sock(sk);
  8     sk->sk_shutdown = SHUTDOWN_MASK;
  9 
 10     /* LISTEN状态处理 */
 11     if (sk->sk_state == TCP_LISTEN) {
 12         /* 设置close状态 */
 13         tcp_set_state(sk, TCP_CLOSE);
 14 
 15         /* Special case. */
 16         /* 清理完成连接队列 */
 17         inet_csk_listen_stop(sk);
 18 
 19         goto adjudge_to_death;
 20     }
 21 
 22     /*  We need to flush the recv. buffs.  We do this only on the
 23      *  descriptor close, not protocol-sourced closes, because the
 24      *  reader process may not have drained the data yet!
 25      */
 26     /* 删除接收队列中用户进程未读取的skb */
 27     while ((skb = __skb_dequeue(&sk->sk_receive_queue)) != NULL) {
 28         u32 len = TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq;
 29 
 30         /* 减去fin的一个序号长度 */
 31         if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)
 32             len--;
 33         data_was_unread += len;
 34         __kfree_skb(skb);
 35     }
 36 
 37     sk_mem_reclaim(sk);
 38 
 39     /* If socket has been already reset (e.g. in tcp_reset()) - kill it. */
 40     /* CLOSE状态 */
 41     if (sk->sk_state == TCP_CLOSE)
 42         goto adjudge_to_death;
 43 
 44     /* As outlined in RFC 2525, section 2.17, we send a RST here because
 45      * data was lost. To witness the awful effects of the old behavior of
 46      * always doing a FIN, run an older 2.1.x kernel or 2.0.x, start a bulk
 47      * GET in an FTP client, suspend the process, wait for the client to
 48      * advertise a zero window, then kill -9 the FTP client, wheee...
 49      * Note: timeout is always zero in such a case.
 50      */
 51     /* 修复状态,断开连接 */
 52     if (unlikely(tcp_sk(sk)->repair)) {
 53         sk->sk_prot->disconnect(sk, 0);
 54     } 
 55     /* 用户进程有数据未读 */
 56     else if (data_was_unread) {
 57         /* Unread data was tossed, zap the connection. */
 58         NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONCLOSE);
 59 
 60         /* 设置为close */
 61         tcp_set_state(sk, TCP_CLOSE);
 62 
 63         /* 发送rst */
 64         tcp_send_active_reset(sk, sk->sk_allocation);
 65     } 
 66     /* lingertime==0,断开连接 */
 67     else if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) {
 68         /* Check zero linger _after_ checking for unread data. */
 69         sk->sk_prot->disconnect(sk, 0);
 70         NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONDATA);
 71     } 
 72     /* 关闭状态转移 */
 73     else if (tcp_close_state(sk)) {
 74         /* We FIN if the application ate all the data before
 75          * zapping the connection.
 76          */
 77 
 78         /* RED-PEN. Formally speaking, we have broken TCP state
 79          * machine. State transitions:
 80          *
 81          * TCP_ESTABLISHED -> TCP_FIN_WAIT1
 82          * TCP_SYN_RECV    -> TCP_FIN_WAIT1 (forget it, it's impossible)
 83          * TCP_CLOSE_WAIT -> TCP_LAST_ACK
 84          *
 85          * are legal only when FIN has been sent (i.e. in window),
 86          * rather than queued out of window. Purists blame.
 87          *
 88          * F.e. "RFC state" is ESTABLISHED,
 89          * if Linux state is FIN-WAIT-1, but FIN is still not sent.
 90          *
 91          * The visible declinations are that sometimes
 92          * we enter time-wait state, when it is not required really
 93          * (harmless), do not send active resets, when they are
 94          * required by specs (TCP_ESTABLISHED, TCP_CLOSE_WAIT, when
 95          * they look as CLOSING or LAST_ACK for Linux)
 96          * Probably, I missed some more holelets.
 97          *                         --ANK
 98          * XXX (TFO) - To start off we don't support SYN+ACK+FIN
 99          * in a single packet! (May consider it later but will
100          * probably need API support or TCP_CORK SYN-ACK until
101          * data is written and socket is closed.)
102          */
103         /* 发送fin */
104         tcp_send_fin(sk);
105     }
106 
107     /* 等待关闭,状态为FIN_WAIT_1 CLOSING LAST_ACK或sk_lingertime超时 */
108     sk_stream_wait_close(sk, timeout);
109 
110 adjudge_to_death:
111     state = sk->sk_state;
112     sock_hold(sk);
113 
114     /* 设置为DEAD状态 */
115     sock_orphan(sk);
116 
117     /* It is the last release_sock in its life. It will remove backlog. */
118     /* 删除控制块的backlog、cb */
119     release_sock(sk);
120 
121 
122     /* Now socket is owned by kernel and we acquire BH lock
123        to finish close. No need to check for user refs.
124      */
125     local_bh_disable();
126     bh_lock_sock(sk);
127     WARN_ON(sock_owned_by_user(sk));
128 
129     /* 增加孤儿计数 */
130     percpu_counter_inc(sk->sk_prot->orphan_count);
131 
132     /* Have we already been destroyed by a softirq or backlog? */
133     /* 被软中断或者backlog销毁了????? */
134     if (state != TCP_CLOSE && sk->sk_state == TCP_CLOSE)
135         goto out;
136 
137     /*    This is a (useful) BSD violating of the RFC. There is a
138      *    problem with TCP as specified in that the other end could
139      *    keep a socket open forever with no application left this end.
140      *    We use a 1 minute timeout (about the same as BSD) then kill
141      *    our end. If they send after that then tough - BUT: long enough
142      *    that we won't make the old 4*rto = almost no time - whoops
143      *    reset mistake.
144      *
145      *    Nope, it was not mistake. It is really desired behaviour
146      *    f.e. on http servers, when such sockets are useless, but
147      *    consume significant resources. Let's do it with special
148      *    linger2    option.                    --ANK
149      */
150 
151     if (sk->sk_state == TCP_FIN_WAIT2) {
152         struct tcp_sock *tp = tcp_sk(sk);
153         /* linger2小于0,无需等待 */
154         if (tp->linger2 < 0) {
155 
156             /* 转到CLOSE */
157             tcp_set_state(sk, TCP_CLOSE);
158             /* 发送rst */
159             tcp_send_active_reset(sk, GFP_ATOMIC);
160             __NET_INC_STATS(sock_net(sk),
161                     LINUX_MIB_TCPABORTONLINGER);
162         } else {
163 
164             /* 获取FIN_WAIT_2超时时间 */
165             const int tmo = tcp_fin_time(sk);
166 
167             /* FIN_WAIT_2超时时间> timewait时间,加FIN_WAIT_2定时器 */
168             if (tmo > TCP_TIMEWAIT_LEN) {
169                 inet_csk_reset_keepalive_timer(sk,
170                         tmo - TCP_TIMEWAIT_LEN);
171             } 
172             /* 小于TIME_WAIT时间,则进入TIME_WAIT */
173             else {
174                 tcp_time_wait(sk, TCP_FIN_WAIT2, tmo);
175                 goto out;
176             }
177         }
178     }
179 
180     /* 未处于CLOSE */
181     if (sk->sk_state != TCP_CLOSE) {
182         sk_mem_reclaim(sk);
183 
184         /* 孤儿数量过多,或者socket内存过多 */
185         if (tcp_check_oom(sk, 0)) {
186             /* 进入CLOSE */
187             tcp_set_state(sk, TCP_CLOSE);
188             /* 发送rst */
189             tcp_send_active_reset(sk, GFP_ATOMIC);
190             __NET_INC_STATS(sock_net(sk),
191                     LINUX_MIB_TCPABORTONMEMORY);
192         }
193     }
194 
195     /* 处于CLOSE */
196     if (sk->sk_state == TCP_CLOSE) {
197         struct request_sock *req = tcp_sk(sk)->fastopen_rsk;
198         /* We could get here with a non-NULL req if the socket is
199          * aborted (e.g., closed with unread data) before 3WHS
200          * finishes.
201          */
202         if (req)
203             reqsk_fastopen_remove(sk, req, false);
204 
205         /* 销毁控制块 */
206         inet_csk_destroy_sock(sk);
207     }
208     /* Otherwise, socket is reprieved until protocol close. */
209 
210 out:
211     bh_unlock_sock(sk);
212     local_bh_enable();
213     sock_put(sk);
214 }
原文地址:https://www.cnblogs.com/wanpengcoder/p/11751647.html