Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【Bug】Disconnect duplicate peer时并没有真正关闭链接 #4406

Open
Tianpingan opened this issue Apr 24, 2024 · 3 comments
Open

【Bug】Disconnect duplicate peer时并没有真正关闭链接 #4406

Tianpingan opened this issue Apr 24, 2024 · 3 comments
Assignees

Comments

@Tianpingan
Copy link

Tianpingan commented Apr 24, 2024

libp2p目录中Service.cpp代码逻辑有问题,在特殊情况下会出现一对节点互相无法联通的。

经过排查,发现是在Disconnect duplicate peer时,并没有真正关闭连接,使得一对节点互相持有对方早已移除的连接,从而无法完成通信。

Service::onConnect中,如果出现duplicate peer,会执行session->disconnect(rock::network::DuplicatePeer)

onConnect函数关键代码如下:

            auto it = m_sessions.find(nodeID);
            if (it != m_sessions.end() && it->second->actived()) {
                SERVICE_LOG(TRACE) << "Disconnect duplicate peer" << LOG_KV("nodeID", nodeID.abridged());
                updateStaticNodes(session->socket(), nodeID);
                session->disconnect(rock::network::DuplicatePeer);
                return;
            }

session的disconnect函数会调用drop函数:

        void Session::disconnect(DisconnectReason _reason) {
            drop(_reason);
        }

在drop函数中,我们发现"drop, call and erase all callbackFunc in this session!"这个日志从未出现过,经分析,是此时m_actived是false,使得drop函数提前退出了,并没有真正去close掉duplicate的peer。

        void Session::drop(DisconnectReason _reason) {
            auto server = m_server.lock();

            if (!m_actived)
                return;

            if (m_readIdleTimer) {
                m_readIdleTimer->cancel();
            }
            if (m_writeIdleTimer) {
                m_writeIdleTimer->cancel();
            }
            m_actived = false;

            int errorCode = P2PExceptionType::Disconnect;
            std::string errorMsg = "Disconnect";
            if (_reason == DuplicatePeer) {
                errorCode = P2PExceptionType::DuplicateSession;
                errorMsg = "DuplicateSession";
            }

            SESSION_LOG(INFO) << "drop, call and erase all callbackFunc in this session!"
                              << LOG_KV("endpoint", nodeIPEndpoint());
            rock::common::core::RecursiveGuard l(x_seq2Callback);
@Tianpingan Tianpingan changed the title 【Bug】Disconnect duplicate peer时并没有真正关闭链接。 【Bug】Disconnect duplicate peer时并没有真正关闭链接 Apr 24, 2024
@bxq2011hust
Copy link
Member

bxq2011hust commented Apr 25, 2024

我检查了代码,你描述的disconnect没有关闭当前的socket是可能的,但逻辑上这个问题不会影响两个节点的链接,因为这个session会被丢弃,当其析构时会关闭socket。
另外这里的逻辑说明新链接是重复的,也就是节点间已经存在一个链接,所以两个节点连接不上是不是找错了原因?

@Tianpingan
Copy link
Author

的逻辑说明新链接是重复的,也就是节点间已经存在一个链接,所以两个节点连接不上是不是找错了原因?

嗯嗯感谢回复,我之后check了一下,这确实不是主要原因,我观察到日志中两个节点在频繁建立链接,所以推测发生两个节点连接不上的可能原因是:

两个链接1和2,A节点认为1先于2建立,所以断了2,而B节点认为2先于1建立,所以断了1,然后都连不上,再尝试链接,循环往复。

具体的例子可能如下:

A收到链接1的第二次握手,认为链接1建立成功,调用onConnect,将链接1添加到session中。
A给B发送链接1的第三次握手
B在收到链接1的第三次握手前,已经收到链接2的第二次握手,调用onConnect,将链接2添加到session中。
B给A发送链接2的第三次握手
B收到链接1的第三次握手,发现session中已经有链接2了,所以断掉链接1
A收到链接2的第三次握手,发现session中已经有链接1了,所以断掉链接2

之后双方发现session均已关闭,又发起互相的链接请求,循环上述过程。

@bxq2011hust
Copy link
Member

@Tianpingan 听起来是有可能发生的,但这个发生的概率应该很低,节点每10s尝试去链接其他节点,除非每次都发生互相连接而处理顺序不同导致断开,否则最终应该还是能建立链接。能否请您提供发生问题时两个节点的日志,我们根据日志来跟进排查这个问题

@bxq2011hust bxq2011hust self-assigned this May 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants