fix(libmsg): close fd-reuse race silently killing short-lived connections
worker 收 EOF 失败后过早清除 busy 标记,事件循环对同一 fd 重复投递任务, 迟到的失败标记经 fd 复用落在新连接上被 _reap_failed 误杀(客户端收到空 EOF)。 失败路径改由 _reap_failed 统一清除 busy 并关闭;_handle_client 增加防重复投递守卫。 memdb 短连接压力测试错误率从 5-9% 降至 0。
This commit is contained in:
1 parent
910ab8aa38
commit
b2ecb8e12b
1 file changed
+8
-5
@@ -331,10 +331,11 @@ private:
|
|||||||
try {
|
try {
|
||||||
task.message = pmsg_recv(task.fd, _config.recv_timeout);
|
task.message = pmsg_recv(task.fd, _config.recv_timeout);
|
||||||
} catch (const MsgException&) {
|
} catch (const MsgException&) {
|
||||||
|
// 不在此清除 busy:fd 保持 busy 直到 _reap_failed 关闭连接。
|
||||||
|
// 旧实现提前清除 busy,EOF 可读性会让事件循环为同一 fd 重复
|
||||||
|
// 投递任务,迟到的失败标记经 fd 复用可能落在新连接上误杀之。
|
||||||
std::lock_guard<std::mutex> flk(_failed_mtx);
|
std::lock_guard<std::mutex> flk(_failed_mtx);
|
||||||
_failed.insert(task.fd);
|
_failed.insert(task.fd);
|
||||||
std::lock_guard<std::mutex> blk(_busy_mtx);
|
|
||||||
_busy.erase(task.fd);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -354,11 +355,12 @@ private:
|
|||||||
failed = true;
|
failed = true;
|
||||||
}
|
}
|
||||||
if (failed) {
|
if (failed) {
|
||||||
|
// 失败连接交由 _reap_failed 统一清除 busy 并关闭,
|
||||||
|
// 不提前恢复 select 监听(同 recv 失败路径,防 fd 复用竞态)。
|
||||||
std::lock_guard<std::mutex> flk(_failed_mtx);
|
std::lock_guard<std::mutex> flk(_failed_mtx);
|
||||||
_failed.insert(task.fd);
|
_failed.insert(task.fd);
|
||||||
}
|
} else {
|
||||||
// 清除 busy 标记,恢复 select 监听
|
// 清除 busy 标记,恢复 select 监听
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(_busy_mtx);
|
std::lock_guard<std::mutex> lock(_busy_mtx);
|
||||||
_busy.erase(task.fd);
|
_busy.erase(task.fd);
|
||||||
}
|
}
|
||||||
@@ -528,6 +530,7 @@ private:
|
|||||||
// 事件循环线程不阻塞接收,防 Slowloris DoS CWE-400)
|
// 事件循环线程不阻塞接收,防 Slowloris DoS CWE-400)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> blk(_busy_mtx);
|
std::lock_guard<std::mutex> blk(_busy_mtx);
|
||||||
|
if (_busy.count(fd)) return; // 已有在途任务,防同一 fd 重复投递(fd 复用竞态)
|
||||||
_busy.insert(fd);
|
_busy.insert(fd);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in new issue
Block a user