Three-Way Handshake

2022/01/21 kernel

Step.1 APP(server)

1.1 Call Graph

sys_listen
│
├──inet_listen
      │
      ├──inet_csk_listen_start
            │
            ├──tcp_v4_hash
                  │
                  ├──inet_hash

1.2 Details

  • inet_csk_listen_start
    • 初始化连接队列inet_connection_sock{}->icsk_accept_queue;
    • sock{}->sk_state设置为TCP_LISTEN状态;
  • inet_hash
    • 将sock{}结构添加到listen hash table — inet_hashinfo{}->listening_hash[]中

 

Step.2 APP(server)

2.1 Call Graph

sys_connect
│
├──inet_stream_connect
      │
      ├──tcp_v4_connect
      │    │
      │    ├──inet_hash_connect
      │    │    │
      │    │    ├──__inet_hash
      │    │
      │    ├──tcp_connect
      │          │
      │          ├──tcp_transmit_skb
      │
      ├──inet_wait_for_connect

2.2 Details

  • inet_csk_wait_for_connect
    • 调度处理器,挂起当前进程,等待连接队列inet_connection_sock{}->icsk_accept_queue变为非NULL;
  • reqsk_queue_get_child
    • 从连接队列inet_connection_sock{}->icsk_accept_queue中获取新连接对应的sock{}结构

 

Step.3 APP(client)

3.1 Call Graph

sys_connect
│
├──inet_stream_connect
      │
      ├──tcp_v4_connect
      │    │
      │    ├──inet_hash_connect
      │    │    │
      │    │    ├──__inet_hash
      │    │
      │    ├──tcp_connect
      │          │
      │          ├──tcp_transmit_skb
      │
      ├──inet_wait_for_connect

3.2 Details

  • tcp_v4_connect
    • sock{}->sk_state设置为TCP_SYN_SENT状态
  • __inet_hash
    • 将sock{}结构添加到ehash table — inet_hashinfo{}->ehash[]中
  • tcp_connect
    • 构造SYN报文
  • tcp_transmit_skb
    • 发送SYN报文
  • inet_wait_for_connect
    • 调度处理器,挂起当前进程,等待sock{}->sk_state切换为非TCP_SYN_SENT状态

 

Step.4 Triggered by pkts(server)

4.1 Call Graph

tcp_v4_rcv
│
├──__inet_lookup
│    │
│    ├──__inet_lookup_established
│    │
│    ├──inet_lookup_listener
│
├──tcp_v4_do_rcv
      │
      ├──tcp_v4_hnd_req
      │    │
      │    ├──inet_csk_search_req
      │    │
      │    ├──__inet_lookup_established
      │
      ├──tcp_rcv_state_process
            │
            ├──tcp_v4_conn_request
                  │
                  ├──tcp_v4_send_synack
                  │
                  ├──inet_csk_reqsk_queue_hash_add

4.2 Details

  • tcp_v4_rcv
    • 接收到SYN报文
  • inet_lookup_listener
    • 在listen hash table — inet_hashinfo{}->listening_hash[]中查找skb对应的sock{}结构

      查找成功

  • inet_csk_search_req
    • 在半连接hash table — listen_sock{}->syn_table[]中查找request_sock{}结构

      首次查找失败

  • tcp_v4_hnd_req
    • 返回原始的sock{}结构
  • tcp_v4_conn_request
    • 申请一个request_sock{}结构
  • tcp_v4_send_synack
    • 构造发送SYN+ACK报文
  • inet_csk_reqsk_queue_hash_add
    • 将request_sock{}结构插入到半连接hash table — listen_sock{}->syn_table[]中

      sock{}->sk_state仍然处于TCP_LISTEN状态

 

Step.5 Triggered by pkts(client)

5.1 Call Graph

tcp_v4_rcv
│
├──__inet_lookup
│    │
│    ├──__inet_lookup_established
│
├──tcp_v4_do_rcv
      │
      ├──tcp_rcv_state_process
            │
            ├──tcp_rcv_synsent_state_process
            │    │
            │    ├──tcp_ack
            │    │
            │    ├──tcp_send_ack
            │
            ├──tcp_data_snd_check

5.2 Details

  • tcp_v4_rcv
    • 接收到SYN+ACK报文
  • __inet_lookup_established
    • 在ehash table — inet_hashinfo{}->ehash[]中查找到对应的sock{}结构

      与Step. 3中调用函数__inet_hash相呼应

  • tcp_rcv_synsent_state_process
    • sock{}->sk_state由TCP_SYN_SENT状态切换为TCP_ESTABLISHED状态
    • 执行sock{}->sk_state_change所指的函数,唤醒等待的所有进程

      与Step. 3中调用函数inet_wait_for_connect相呼应,唤醒client端应用程序

  • tcp_send_ack
    • 发送ACK报文

 

Step.6 Triggered by pkts(server)

6.1 Call Graph

tcp_v4_rcv
│
├──__inet_lookup
│    │
│    ├──__inet_lookup_established
│    │
│    ├──inet_lookup_listener
│
├──tcp_v4_do_rcv
      │
      ├──tcp_v4_hnd_req
      │    │
      │    ├──inet_csk_search_req
      │    │
      │    ├──tcp_check_req
      │          │
      │          ├──tcp_v4_syn_recv_sock
      │          │    │
      │          │    ├──tcp_create_openreq_child
      │          │    │
      │          │    ├──__inet_hash
      │          │
      │          ├──inet_csk_reqsk_queue_unlink
      │          │
      │          ├──inet_csk_reqsk_queue_add
      │
      ├──tcp_child_process
            │
            ├──tcp_rcv_state_process
                  │
                  ├──tcp_ack
                  │
                  ├──tcp_data_queue
                  │    │
                  │    ├──tcp_event_data_recv
                  │    │
                  │    ├──tcp_ofo_queue
                  │
                  ├──tcp_data_snd_check
                  │
                  ├──tcp_ack_snd_check

6.2 Details

  • tcp_v4_rcv
    • 接收到ACK报文
  • inet_lookup_listener
    • 在listen hash table — inet_hashinfo{}->listening_hash[]中查找skb对应的sock{}结构

      查找成功

  • inet_csk_search_req
    • 在半连接hash table — listen_sock{}->syn_table[]中查找request_sock{}结构

      与Step. 4中调用函数inet_csk_reqsk_queue_hash_add相呼应,第二次查找成功,返回之前新建的request_sock{}结构

  • tcp_create_openreq_child
    • 创建一个新sock{}结构
    • 新sock{}结构的sock{}->sk_state设置为TCP_SYN_RECV状态
  • inet_csk_reqsk_queue_unlink
    • 将request_sock{}结构从半连接hash table — listen_sock{}->syn_table[]中移除
  • inet_csk_reqsk_queue_add
    • 将request_sock{}结构挂载到连接队列inet_connection_sock{}->icsk_accept_queue中

      与Step. 2中调用函数inet_csk_wait_for_connect相呼应

  • tcp_check_req
    • 最终会返回新创建的sock{}结构
  • tcp_rcv_state_process
    • 这里会将新创建的sock{}结构的sock{}->sk_state由TCP_SYN_RECV状态切换为TCP_ESTABLISHED状态
  • tcp_data_snd_check
    • 检查是否有数据可以发送
  • tcp_ack_snd_check
    • 检查是否需要发送ACK报文
  • tcp_child_process
    • 最后会唤醒等待原sock{}结构的进程

      与Step. 2中调用函数inet_csk_wait_for_connect相呼应

 

Search

    Table of Contents