将状态设置为 TCP_SYN_RECV 后内核如何继续进行三向握手
我试图了解 TCP 三向握手在 Linux 内核版本 2.6.33 中是如何实现的。
我从函数accept()开始,这导致我:
accept()==>sys_accept()==>sys_accept4()==>inet_accept()==>inet_csk_accept()
现在我陷入了inet_csk_accept( )。
struct sock *inet_csk_accept(struct sock *sk, int flags, int *err)
{
struct inet_connection_sock *icsk = inet_csk(sk);
struct sock *newsk;
int error;
lock_sock(sk);
/* We need to make sure that this socket is listening,
* and that it has something pending.
*/
error = -EINVAL;
if (sk->sk_state != TCP_LISTEN)
goto out_err;
/* Find already established connection */
if (reqsk_queue_empty(&icsk->icsk_accept_queue)) {
long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
/* If this is a non blocking socket don't sleep */
error = -EAGAIN;
if (!timeo)
goto out_err;
error = inet_csk_wait_for_connect(sk, timeo);
if (error)
goto out_err;
}
newsk = reqsk_queue_get_child(&icsk->icsk_accept_queue, sk);
WARN_ON(newsk->sk_state == TCP_SYN_RECV);
out:
release_sock(sk);
return newsk;
out_err:
newsk = NULL;
*err = error;
goto out;
}
我的问题是程序何时进入
WARN_ON(newsk->sk_state == TCP_SYN_RECV);
三向握手已完成?
服务器发送ACK的代码在哪里?
服务器确认客户端ACK的代码在哪里?
或者如果我一开始就错了,那么三向握手是否全部在 accpet() 内部实现?
谢谢
I am trying to understand how the TCP three way handshake is implemented in Linux kernel, version 2.6.33.
I started with function accept() which leads me to:
accept()==>sys_accept()==>sys_accept4()==>inet_accept()==>inet_csk_accept()
Now I am stucked in inet_csk_accept().
struct sock *inet_csk_accept(struct sock *sk, int flags, int *err)
{
struct inet_connection_sock *icsk = inet_csk(sk);
struct sock *newsk;
int error;
lock_sock(sk);
/* We need to make sure that this socket is listening,
* and that it has something pending.
*/
error = -EINVAL;
if (sk->sk_state != TCP_LISTEN)
goto out_err;
/* Find already established connection */
if (reqsk_queue_empty(&icsk->icsk_accept_queue)) {
long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
/* If this is a non blocking socket don't sleep */
error = -EAGAIN;
if (!timeo)
goto out_err;
error = inet_csk_wait_for_connect(sk, timeo);
if (error)
goto out_err;
}
newsk = reqsk_queue_get_child(&icsk->icsk_accept_queue, sk);
WARN_ON(newsk->sk_state == TCP_SYN_RECV);
out:
release_sock(sk);
return newsk;
out_err:
newsk = NULL;
*err = error;
goto out;
}
My question is when the programs goes to
WARN_ON(newsk->sk_state == TCP_SYN_RECV);
the three way handshake already finished?
Where is the code that the server sends the ACK?
Where is the code that the server confirms the ACK from client?
or if I was wrong at the beginning, is the three way handshake is implemented all inside accpet()?
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
TCP 的实际套接字逻辑位于
套接字状态机中,位于
实现所有套接字状态转换(包括三向握手)的函数中。
该函数的调用方式如下:
对于每个收到的 TCP 数据包。该调用由接口驱动程序(即网络适配器的驱动程序)发起。
accept()
仅等待套接字状态从TCP_LISTEN
更改为TCP_ESTABLISHED
。状态 TCP_LISTEN 由listen()
设置。实际的状态更改是在tcp_rcv_state_process
中执行的。所以这个过程是异步的。调用
accept()
不会直接导致调用tcp_rcv_state_process
Actual socket logic for TCP located in
State machine for socket is located in function
which implement all socket state transitions (including three way handshake).
This function is called this way:
for every received TCP packet. This call is initiated by interface driver (i.e. driver for network adapter).
accept()
only waits for socket state to be changed fromTCP_LISTEN
toTCP_ESTABLISHED
. And state TCP_LISTEN is set bylisten()
. Actual state change is performed intcp_rcv_state_process
.So this process is asynchronous. Call to
accept()
does not directly lead to call totcp_rcv_state_process
状态转换涉及许多功能。但一般来说,有一个通用函数只改变状态:tcp_set_state()。
在 net/ipv4/*.c 源中执行 grep:
现在随机选择其中之一:
tcp.c:tcp_fin(),它处理 FIN 状态转换:
所以您可以从上面看到之前的(即 TCP_SYN_RECV)和通过 tcp_set_state() 函数更改状态后。
在另一个函数(也是tcp_input.c)中:
这里是通过调用tcp_set_state()对TCP_SYN_RECV进行设置,然后继续进行其他处理。
上述任一场景都涵盖了 TCP_SYN_RECV 状态之后的状态处理。
Many functions is involved in the state transition. But in general, there is one general function that just change the state: tcp_set_state().
Doing a grep in net/ipv4/*.c sources:
and now randomly picked one of them:
tcp.c: tcp_fin(), which handle the FIN state transition:
So you can see from above the before (ie, TCP_SYN_RECV) and after state changed by the tcp_set_state() function.
In another function (also tcp_input.c):
Here is the setting to TCP_SYN_RECV via calling tcp_set_state(), and then it continues with other processing as well.
Either one of the above scenario covers the state processing after the TCP_SYN_RECV state.