Fork me on GitHub

Coding Poineer

Coding Poineer

Coding Poineer

Coding Poineer

Coding Poineer

Coding Poineer

Coding Poineer

Coding Poineer

Coding Poineer

Coding Poineer

Coding Poineer

深入理解TCP协议及其源代码

TCP三次握手

三次握手(Three-way Handshake),是指建立一个TCP连接时,需要客户端和服务器总共发送3个包。为的是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号并交换TCP窗口大小信息,在socket编程中,客户端执行connect()时,将触发三次握手
握手过程中传送的包里不包含数据,三次握手完毕后,客户端不服务器才正式开始传送 数据。理想状态下,TCP连接一旦建立,在通信双方中的任何一方主劢关闭连接之前,TCP 连接都将被一直保持下去。断开连接时服务器和客户端均可以主劢发起断开TCP连接的请求。

  1. 第一次握手:建立连接。客户端发送连接 请求报文段,将SYN位置为1,Sequence Number为x;然后,客户端迚入 SYN_SEND状态,等待服务器的确认。即 A发送信息给B。
  2. 第二次握手:服务器收到客户端的SYN报 文段,需要对这个SYN报文段迚行确认。 即B收到连接信息后向A返回确认信息。
  3. 第三次握手:客户端收到服务器的 (SYN+ACK)报文段,并向服务器发送 ACK报文段。即A收到确认信息后再次向B 返回确认连接信

源码分析

客户端申请TCP连接

'''

int __sys_connect(int fd, struct sockaddr __user *uservaddr, int addrlen)
{
    struct socket *sock;
    struct sockaddr_storage address;
    int err, fput_needed;
    sock = sockfd_lookup_light(fd, &err, &fput_needed);
    if (!sock)
        goto out;
    err = move_addr_to_kernel(uservaddr, addrlen, &address);
    if (err < 0)
        goto out_put;
    err =
        security_socket_connect(sock, (struct sockaddr *)&address, addrlen);
    if (err)
        goto out_put;
    err = sock->ops->connect(sock, (struct sockaddr *)&address, addrlen,
                 sock->file->f_flags);
	out_put:
    fput_light(sock->file, fput_needed);
	out:
    return err;
}

'''

客户端发送SYN报文

'''

int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
struct sockaddr_in *usin = (struct sockaddr_in *)uaddr;
struct inet_sock *inet = inet_sk(sk);
struct tcp_sock *tp = tcp_sk(sk);
__be16 orig_sport, orig_dport;
__be32 daddr, nexthop;
struct flowi4 *fl4;
struct rtable *rt;
int err;
struct ip_options_rcu *inet_opt;
struct inet_timewait_death_row *tcp_death_row = &sock_net(sk)->ipv4.tcp_death_row;

if (addr_len < sizeof(struct sockaddr_in))
    return -EINVAL;

if (usin->sin_family != AF_INET)
    return -EAFNOSUPPORT;

nexthop = daddr = usin->sin_addr.s_addr;
inet_opt = rcu_dereference_protected(inet->inet_opt,
                     lockdep_sock_is_held(sk));
if (inet_opt && inet_opt->opt.srr) {
    if (!daddr)
        return -EINVAL;
    nexthop = inet_opt->opt.faddr;
}

orig_sport = inet->inet_sport;
orig_dport = usin->sin_port;
fl4 = &inet->cork.fl.u.ip4;
rt = ip_route_connect(fl4, nexthop, inet->inet_saddr,
              RT_CONN_FLAGS(sk), sk->sk_bound_dev_if,
              IPPROTO_TCP,
              orig_sport, orig_dport, sk);
if (IS_ERR(rt)) {
    err = PTR_ERR(rt);
    if (err == -ENETUNREACH)
        IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES);
    return err;
}

if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) {
    ip_rt_put(rt);
    return -ENETUNREACH;
}

if (!inet_opt || !inet_opt->opt.srr)
    daddr = fl4->daddr;

if (!inet->inet_saddr)
    inet->inet_saddr = fl4->saddr;
sk_rcv_saddr_set(sk, inet->inet_saddr);

if (tp->rx_opt.ts_recent_stamp && inet->inet_daddr != daddr) {
    /* Reset inherited state */
    tp->rx_opt.ts_recent       = 0;
    tp->rx_opt.ts_recent_stamp = 0;
    if (likely(!tp->repair))
        tp->write_seq       = 0;
}

inet->inet_dport = usin->sin_port;
sk_daddr_set(sk, daddr);

inet_csk(sk)->icsk_ext_hdr_len = 0;
if (inet_opt)
    inet_csk(sk)->icsk_ext_hdr_len = inet_opt->opt.optlen;

tp->rx_opt.mss_clamp = TCP_MSS_DEFAULT;

tcp_set_state(sk, TCP_SYN_SENT);
err = inet_hash_connect(tcp_death_row, sk);
if (err)
    goto failure;

sk_set_txhash(sk);

rt = ip_route_newports(fl4, rt, orig_sport, orig_dport,
               inet->inet_sport, inet->inet_dport, sk);
if (IS_ERR(rt)) {
    err = PTR_ERR(rt);
    rt = NULL;
    goto failure;
}

sk->sk_gso_type = SKB_GSO_TCPV4;
sk_setup_caps(sk, &rt->dst);
rt = NULL;

if (likely(!tp->repair)) {
    if (!tp->write_seq)
        tp->write_seq = secure_tcp_seq(inet->inet_saddr,
                           inet->inet_daddr,
                           inet->inet_sport,
                           usin->sin_port);
    tp->tsoffset = secure_tcp_ts_off(sock_net(sk),
                     inet->inet_saddr,
                     inet->inet_daddr);
}

inet->inet_id = tp->write_seq ^ jiffies;

if (tcp_fastopen_defer_connect(sk, &err))
    return err;
if (err)
    goto failure;

err = tcp_connect(sk);

if (err)
    goto failure;

return 0;

failure:

tcp_set_state(sk, TCP_CLOSE);
ip_rt_put(rt);
sk->sk_route_caps = 0;
inet->inet_dport = 0;
return err;
}

'''

服务器等待连接请求

'''

struct sock *inet_csk_accept(struct sock *sk, int flags, int *err, bool kern)
{
struct inet_connection_sock *icsk = inet_csk(sk);
struct request_sock_queue *queue = &icsk->icsk_accept_queue;
struct request_sock *req;
struct sock *newsk;
int error;

lock_sock(sk);

error = -EINVAL;
if (sk->sk_state != TCP_LISTEN)
    goto out_err;

if (reqsk_queue_empty(queue)) {
    long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);

    error = -EAGAIN;
    if (!timeo)
        goto out_err;

    error = inet_csk_wait_for_connect(sk, timeo);
    if (error)
        goto out_err;
}
req = reqsk_queue_remove(queue, sk);
newsk = req->sk;

if (sk->sk_protocol == IPPROTO_TCP &&
    tcp_rsk(req)->tfo_listener) {
    spin_lock_bh(&queue->fastopenq.lock);
    if (tcp_rsk(req)->tfo_listener) {
        req->sk = NULL;
        req = NULL;
    }
    spin_unlock_bh(&queue->fastopenq.lock);
}
out:
release_sock(sk);
if (req)
    reqsk_put(req);
return newsk;
out_err:
newsk = NULL;
req = NULL;
*err = error;
goto out;
}

'''

服务器接收SYN,发送SYN+ACK

'''

int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
{
struct sock *rsk;

if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
    struct dst_entry *dst = sk->sk_rx_dst;

    sock_rps_save_rxhash(sk, skb);
    sk_mark_napi_id(sk, skb);
    if (dst) {
        if (inet_sk(sk)->rx_dst_ifindex != skb->skb_iif ||
            !dst->ops->check(dst, 0)) {
            dst_release(dst);
            sk->sk_rx_dst = NULL;
        }
    }
    tcp_rcv_established(sk, skb);
    return 0;
}

if (tcp_checksum_complete(skb))
    goto csum_err;

if (sk->sk_state == TCP_LISTEN) {
    struct sock *nsk = tcp_v4_cookie_check(sk, skb);

    if (!nsk)
        goto discard;
    if (nsk != sk) {
        if (tcp_child_process(sk, nsk, skb)) {
            rsk = nsk;
            goto reset;
        }
        return 0;
    }
} else
    sock_rps_save_rxhash(sk, skb);

if (tcp_rcv_state_process(sk, skb)) {
    rsk = sk;
    goto reset;
}
return 0;

reset:
tcp_v4_send_reset(rsk, skb);
discard:
kfree_skb(skb);
return 0;

csum_err:
TCP_INC_STATS(sock_net(sk), TCP_MIB_CSUMERRORS);
TCP_INC_STATS(sock_net(sk), TCP_MIB_INERRS);
goto discard;
}

'''

客户端收到SYN+ACK,发送ACK

'''

static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
                                     const struct tcphdr *th, unsigned int len)
{   
       tcp_send_ack(sk);
}
posted @ 2019-12-26 16:22  365/24/60  阅读(209)  评论(0编辑  收藏  举报