Skip to content

feat: Add function for sending fd#1561

Merged
dengbo11 merged 2 commits into
OpenAtom-Linyaps:masterfrom
ComixHe:master
Jan 22, 2026
Merged

feat: Add function for sending fd#1561
dengbo11 merged 2 commits into
OpenAtom-Linyaps:masterfrom
ComixHe:master

Conversation

@ComixHe

@ComixHe ComixHe commented Jan 16, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @ComixHe, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces core functionality for inter-process communication (IPC) by enabling the transfer of file descriptors (FDs) between processes using Unix domain sockets. This new capability, accompanied by a robust testing suite, enhances the system's ability to securely and efficiently share resources and data across process boundaries.

Highlights

  • New File Descriptor Transfer Functions: Introduced sendFdWithPayload and recvFdWithPayload functions within linglong::common::socket to facilitate the secure and robust transfer of file descriptors along with arbitrary payload data between processes using Unix domain sockets.
  • Robust Error Handling: The new socket functions incorporate comprehensive error handling, including retries on EINTR (interrupted system calls) and detailed error messages using tl::expected for better reliability.
  • Comprehensive Unit Testing: A dedicated SocketFdTest suite has been added, covering various scenarios such as normal cross-process transfer, handling of invalid file descriptors, payload truncation, signal interruption recovery, and large payload handling, ensuring the stability and correctness of the new functionality.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces new functionality for sending and receiving file descriptors over sockets, along with corresponding tests. The implementation is solid and covers important aspects like handling EINTR. The tests are also quite comprehensive, covering normal operation, edge cases, and even signal interruptions.

My review includes a few suggestions for improvement:

  • Using thread-safe methods for error string retrieval in socket.cpp.
  • Improving test robustness in socket_test.cpp by using waitpid instead of wait.
  • Using sigaction instead of signal for better portability in tests.

Overall, this is a good addition to the common library.

}();

if (n < 0) {
return tl::make_unexpected(std::string{ "Failed to receive message" } + ::strerror(errno));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The ::strerror function is not thread-safe, which can lead to race conditions and incorrect error messages in a multithreaded environment. A better, thread-safe alternative in C++ is to use std::system_category().message(errno), which requires including the <system_error> header. This also provides an opportunity to make the error message more readable.

Suggested change
return tl::make_unexpected(std::string{ "Failed to receive message" } + ::strerror(errno));
return tl::make_unexpected("Failed to receive message: " + std::system_category().message(errno));

}();

if (n < 0) {
return tl::make_unexpected("sendmsg failed: " + std::string(strerror(errno)));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

As in recvFdWithPayload, strerror is not thread-safe. It's recommended to use a thread-safe alternative like std::system_category().message(errno) from the <system_error> header.

Suggested change
return tl::make_unexpected("sendmsg failed: " + std::string(strerror(errno)));
return tl::make_unexpected("sendmsg failed: " + std::system_category().message(errno));

close(sv[0]);
auto res = recvFdWithPayload(sv[1], 1024);
EXPECT_FALSE(res.has_value());
wait(nullptr);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using wait(nullptr) waits for any child process to terminate, which can be imprecise. It's better practice to use waitpid() with the specific child's process ID. This allows you to verify that the correct child process is being waited for and to check its exit status, making the test more robust. This advice applies to other tests in this file that use fork() and wait(nullptr).


TEST_F(SocketFdTest, SignalInterruptionRecovery)
{
auto handler = signal(SIGUSR1, [](int) { });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The signal() function has implementation-defined semantics across different systems, which can make its behavior non-portable. For reliable and portable signal handling, it is strongly recommended to use sigaction() instead.

@codecov

codecov Bot commented Jan 16, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 36.84211% with 72 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
libs/common/src/linglong/common/socket.cpp 53.42% 13 Missing and 21 partials ⚠️
libs/utils/src/linglong/utils/cmd.cpp 0.00% 10 Missing ⚠️
libs/utils/src/linglong/utils/namespace.cpp 0.00% 8 Missing ⚠️
libs/utils/src/linglong/utils/filelock.cpp 16.66% 5 Missing ⚠️
libs/utils/src/linglong/utils/file.cpp 0.00% 4 Missing ⚠️
libs/linglong/src/linglong/cli/cli.cpp 0.00% 2 Missing ⚠️
libs/linglong/src/linglong/package/uab_file.cpp 0.00% 2 Missing ⚠️
...g/src/linglong/package_manager/package_manager.cpp 0.00% 2 Missing ⚠️
libs/utils/src/linglong/utils/env.cpp 0.00% 2 Missing ⚠️
apps/ll-cli/src/main.cpp 0.00% 1 Missing ⚠️
... and 2 more
Files with missing lines Coverage Δ
libs/common/src/linglong/common/error.cpp 100.00% <100.00%> (ø)
libs/utils/src/linglong/utils/error/error.h 41.34% <ø> (ø)
apps/ll-cli/src/main.cpp 0.00% <0.00%> (ø)
libs/linglong/src/linglong/package/layer_file.cpp 29.09% <0.00%> (ø)
libs/utils/src/linglong/utils/hooks.cpp 0.00% <0.00%> (ø)
libs/linglong/src/linglong/cli/cli.cpp 1.00% <0.00%> (ø)
libs/linglong/src/linglong/package/uab_file.cpp 57.60% <0.00%> (ø)
...g/src/linglong/package_manager/package_manager.cpp 1.38% <0.00%> (ø)
libs/utils/src/linglong/utils/env.cpp 57.89% <0.00%> (ø)
libs/utils/src/linglong/utils/file.cpp 27.95% <0.00%> (ø)
... and 4 more
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request adds functionality for sending and receiving file descriptors over Unix domain sockets using the SCM_RIGHTS mechanism. The implementation provides two main functions: sendFdWithPayload for sending a file descriptor with an associated payload string, and recvFdWithPayload for receiving them.

Changes:

  • Added socket.h and socket.cpp to implement file descriptor passing over Unix sockets
  • Added comprehensive test suite with 8 test cases covering normal operation, error conditions, edge cases, and signal handling
  • Updated CMake build files to include the new source and test files

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 16 comments.

Show a summary per file
File Description
libs/common/src/linglong/common/socket.h Defines the public API for socket fd passing with SocketData struct and two main functions
libs/common/src/linglong/common/socket.cpp Implements fd passing using sendmsg/recvmsg with ancillary data and EINTR handling
libs/linglong/tests/ll-tests/src/linglong/common/socket_test.cpp Comprehensive test suite covering cross-process transfer, error handling, truncation, signals, and edge cases
libs/common/CMakeLists.txt Adds new socket source files to the build
libs/linglong/tests/ll-tests/CMakeLists.txt Adds new socket test file to the test build

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +18 to +20

tl::expected<SocketData, std::string> recvFdWithPayload(int fd, std::size_t bufSize = 4096);

Copilot AI Jan 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The public API functions recvFdWithPayload and sendFdWithPayload lack documentation. Add docstrings explaining their purpose, parameters, return values, and error conditions. This is especially important for API functions that will be used by other components.

Suggested change
tl::expected<SocketData, std::string> recvFdWithPayload(int fd, std::size_t bufSize = 4096);
/**
* @brief Receives a file descriptor and an optional payload from a socket.
*
* This function expects the peer to send one file descriptor along with an
* associated payload (typically a small control message) over a socket
* that supports passing file descriptors (e.g. a UNIX domain socket).
*
* @param fd
* A valid, connected socket file descriptor to receive from.
* @param bufSize
* Maximum number of bytes to read for the payload. If the incoming
* payload is larger than this value, the behavior is implementation
* defined (e.g. it may be truncated or treated as an error). The
* default buffer size is 4096 bytes.
*
* @return tl::expected<SocketData, std::string>
* - On success, contains a SocketData instance with the received file
* descriptor and payload string. The caller is responsible for
* managing (and eventually closing) the received file descriptor.
* - On failure, contains a human-readable error message describing the
* problem (for example, an invalid socket, protocol error, or system
* call failure).
*/
tl::expected<SocketData, std::string> recvFdWithPayload(int fd, std::size_t bufSize = 4096);
/**
* @brief Sends a file descriptor and an associated payload over a socket.
*
* This function sends the given file descriptor together with the provided
* payload (typically a small control message) over a socket that supports
* passing file descriptors (e.g. a UNIX domain socket).
*
* @param socketFd
* A valid, connected socket file descriptor to send on.
* @param fd
* The file descriptor to send to the peer. Ownership of this file
* descriptor is not transferred by this function; the caller remains
* responsible for closing it unless otherwise specified by the
* surrounding protocol.
* @param payload
* A string payload to send alongside the file descriptor. Very large
* payloads may fail depending on the underlying implementation or OS
* limits.
*
* @return tl::expected<void, std::string>
* - On success, contains no value (i.e. an engaged expected<void>).
* - On failure, contains a human-readable error message describing the
* problem (for example, an invalid argument, protocol error, or
* system call failure).
*/

Copilot uses AI. Check for mistakes.
Comment on lines +77 to +82
if (fork() == 0) {
close(sv[1]);
std::string data = "just-text-no-fd";
ASSERT_NE(write(sv[0], data.data(), data.size()), -1);
close(sv[0]);
_exit(0);

Copilot AI Jan 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The child process doesn't check the return value of sendFdWithPayload before exiting. If the send operation fails, the test may not accurately detect the failure. The child should exit with EXIT_FAILURE if sendFdWithPayload returns an error.

Copilot uses AI. Check for mistakes.
close(sv[0]);
auto res = recvFdWithPayload(sv[1], 1024);
EXPECT_FALSE(res.has_value());
wait(nullptr);

Copilot AI Jan 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test doesn't verify the child process exit status. If the child process encounters an error, the test may still pass. Consider using waitpid with a status variable and checking WEXITSTATUS.

Copilot uses AI. Check for mistakes.
close(res->fd);
}

wait(nullptr);

Copilot AI Jan 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test doesn't verify the child process exit status. If the child process encounters an assertion failure with EXPECT_TRUE, the test may still pass because wait(nullptr) doesn't check the exit status. Consider using waitpid with a status variable and checking WEXITSTATUS.

Copilot uses AI. Check for mistakes.
close(res->fd);
}

wait(nullptr);

Copilot AI Jan 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test doesn't verify the child process exit status. If the child process encounters an error, the test may still pass. Consider using waitpid with a status variable and checking WEXITSTATUS.

Copilot uses AI. Check for mistakes.
Comment on lines +12 to +20

struct SocketData
{
int fd;
std::string payload;
};

tl::expected<SocketData, std::string> recvFdWithPayload(int fd, std::size_t bufSize = 4096);

Copilot AI Jan 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SocketData struct and the public functions lack documentation. Consider adding docstrings to explain:

  • The purpose of SocketData and ownership semantics of the fd member
  • What recvFdWithPayload and sendFdWithPayload do
  • Parameter descriptions (what each parameter represents)
  • Return value semantics (when errors occur, what the caller should do with the fd)
  • Caller responsibilities (e.g., closing the received fd)
Suggested change
struct SocketData
{
int fd;
std::string payload;
};
tl::expected<SocketData, std::string> recvFdWithPayload(int fd, std::size_t bufSize = 4096);
/**
* @brief Container for a file descriptor and an associated payload.
*
* The @c fd member represents a file descriptor that is sent or received
* over a socket together with the textual @c payload.
*
* Ownership of @c fd is not managed automatically by this struct. When
* a @c SocketData instance is returned from @c recvFdWithPayload on
* success, ownership of the contained file descriptor is transferred
* to the caller. The caller is then responsible for closing the
* descriptor when it is no longer needed.
*
* A value of @c -1 for @c fd indicates that there is no valid file
* descriptor associated with this instance.
*/
struct SocketData
{
int fd;
std::string payload;
};
/**
* @brief Receive a file descriptor and an associated payload over a socket.
*
* This function reads from a socket that supports passing file descriptors
* (for example, a UNIX domain socket) and attempts to receive a single file
* descriptor along with a textual payload.
*
* @param fd
* The socket file descriptor to read from.
* @param bufSize
* The maximum number of bytes to read for the payload. The payload
* may be truncated to this size.
*
* @return
* On success, returns a @c SocketData value containing the received
* file descriptor and payload. Ownership of the returned file descriptor
* is transferred to the caller, who is responsible for closing it when
* it is no longer needed.
*
* On failure, returns an @c unexpected containing a human-readable
* error message. In that case, no ownership of any file descriptor
* is transferred to the caller, and the caller MUST NOT attempt to
* close any descriptor that would have been received.
*/
tl::expected<SocketData, std::string> recvFdWithPayload(int fd, std::size_t bufSize = 4096);
/**
* @brief Send a file descriptor and an associated payload over a socket.
*
* This function sends a single file descriptor along with a textual payload
* over a socket that supports passing file descriptors (for example, a
* UNIX domain socket).
*
* @param socketFd
* The socket file descriptor to send the data over.
* @param fd
* The file descriptor to send. The caller retains ownership of this
* descriptor regardless of success or failure and is responsible for
* closing it when appropriate.
* @param payload
* The textual payload to be sent alongside the file descriptor.
*
* @return
* On success, returns an empty (engaged) @c tl::expected<void, std::string>.
*
* On failure, returns an @c unexpected containing a human-readable error
* message. In that case, the caller still owns @p fd and must decide
* whether to retry the operation or close the descriptor.
*/

Copilot uses AI. Check for mistakes.
}();

if (n < 0) {
return tl::make_unexpected(std::string{ "Failed to receive message" } + ::strerror(errno));

Copilot AI Jan 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message concatenation is missing a separator or proper formatting. The error message will appear as "Failed to receive messageBad file descriptor" (or similar) without spacing. Consider using std::format or adding proper spacing, e.g., "Failed to receive message: " with a colon and space.

Suggested change
return tl::make_unexpected(std::string{ "Failed to receive message" } + ::strerror(errno));
return tl::make_unexpected(std::string{ "Failed to receive message: " } + ::strerror(errno));

Copilot uses AI. Check for mistakes.

int received_fd{ -1 };
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);

Copilot AI Jan 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If cmsg is nullptr, the function returns an error but the received_fd is not closed. However, in this specific case, if there's no control message header, no file descriptor was received, so received_fd remains -1 and doesn't need to be closed. This is correct but could benefit from a code comment explaining this for maintainability.

Suggested change
// If there is no control message header, no file descriptor was received.
// In this case received_fd remains -1 and does not need to be closed.

Copilot uses AI. Check for mistakes.
const std::string large_payload(65536, 'B');
if (fork() == 0) {
close(sv[1]);
auto ret = sendFdWithPayload(sv[0], STDIN_FILENO, large_payload);

Copilot AI Jan 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test doesn't check the return value of sendFdWithPayload. If the send fails, the child process exits with status 0 anyway, which could lead to false positives in the test. Consider checking the result and exiting with a failure status if the send operation fails.

Suggested change
auto ret = sendFdWithPayload(sv[0], STDIN_FILENO, large_payload);
auto ret = sendFdWithPayload(sv[0], STDIN_FILENO, large_payload);
if (!ret.has_value()) {
close(sv[0]);
_exit(1);
}

Copilot uses AI. Check for mistakes.
}

if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
return tl::make_unexpected("Not ancillary data with file descriptor");

Copilot AI Jan 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message "Not ancillary data with file descriptor" is grammatically incorrect. It should be "No ancillary data with file descriptor" or "Not an ancillary message with file descriptor" or "Invalid ancillary data: expected file descriptor".

Suggested change
return tl::make_unexpected("Not ancillary data with file descriptor");
return tl::make_unexpected("Invalid ancillary data: expected file descriptor");

Copilot uses AI. Check for mistakes.
Signed-off-by: ComixHe <ComixHe1895@outlook.com>
Signed-off-by: ComixHe <ComixHe1895@outlook.com>
@deepin-ci-robot

Copy link
Copy Markdown
Collaborator

deepin pr auto review

这份代码 diff 主要进行了以下变更:

  1. 创建了新的 linglong::common::error 命名空间,将 errorString 函数从 linglong::utils 移动到了 linglong::common::error
  2. 新增了 linglong::common::socket 模块,用于处理文件描述符和数据的 socket 传输(recvFdWithPayload, sendFdWithPayload)。
  3. 全局替换了对 errorString 的调用,改为 common::error::errorString
  4. 新增了针对 socket 功能的单元测试。

以下是对代码的详细审查意见:

1. 语法与逻辑

  • libs/common/src/linglong/common/socket.cpp - recvFdWithPayload 函数:

    • 问题: 在 recvFdWithPayload 中,当 ioctl 检查到有更多数据(bytes_available > 0)时,仅设置 isTruncated = true 并返回。这会导致接收端只读取了部分数据,而剩余数据留在 socket 缓冲区中。如果调用者不处理 isTruncated 标志并继续读取,可能会导致后续数据错乱或丢失。
    • 改进建议: 考虑到 recvmsg 的特性(一次性读取),如果数据超过缓冲区大小,MSG_TRUNC 标志通常会被内核设置。这里的逻辑是为了处理 bufSize 恰好等于读取字节数 n 的情况,这是一种边界检查。
    • 代码逻辑: 逻辑上看起来是正确的,它试图检测缓冲区是否恰好填满但还有数据的情况。不过,对于 SocketData 结构体,调用者需要明确检查 more_data(代码中定义为 isTruncated,但在头文件中结构体字段名为 more_data)。
    • 不一致: 在 socket.h 中,struct SocketData 的字段名为 more_data,但在 socket.cpp 中使用的是 isTruncated 变量名进行构造。虽然代码能编译通过(因为构造函数参数顺序匹配),但这降低了可读性。
    • 建议: 将 socket.cpp 中的 isTruncated 变量重命名为 more_data 以保持一致性,或者修改结构体定义。
  • libs/common/src/linglong/common/socket.cpp - sendFdWithPayload 函数:

    • 问题: sendmsg 在循环中调用,但辅助数据(文件描述符 fd)的发送只处理了一次(通过 fdSent 标志控制)。这是正确的,因为文件描述符通常只需要发送一次。但是,如果 sendmsg 在发送辅助数据的过程中只发送了部分辅助数据(虽然对于 SCM_RIGHTS 这种控制消息,内核通常要么全收要么不收,但在极端网络或复杂情况下),标准行为可能需要更复杂的处理。不过对于 Unix Domain Socket 传递文件描述符,原子性通常由内核保证。
    • 逻辑: 逻辑正确,能够处理 EINTR 和部分数据发送的情况。

2. 代码质量

  • 命名空间与头文件保护:

    • linglong::common::errorlinglong::common::socket 的引入是合理的,符合模块化设计。
    • #pragma once 使用正确。
  • 错误处理:

    • 使用了 tl::expected 进行错误处理,比异常或返回错误码更现代且安全,值得肯定。
    • 错误信息拼接使用了 errorString(errno),提供了详细的系统错误原因,有助于调试。
  • 注释与文档:

    • 新增的 error.hsocket.h 缺少函数注释。虽然函数名比较直观,但建议添加 Doxygen 风格的注释,说明参数含义、返回值含义以及可能的副作用。
  • 代码重复:

    • recvFdWithPayloadsendFdWithPayload 中都有 if (n < 0 && errno == EINTR) { continue; } 的逻辑。这是处理系统调用被信号中断的标准做法,虽然重复,但封装起来可能反而增加复杂度,当前写法可以接受。

3. 代码性能

  • 内存分配:

    • recvFdWithPayload 中使用 std::string buffer(bufSize, '\0') 预分配内存。这比动态增长更高效,避免了多次重分配。
    • sendFdWithPayloadcontrol_buf 使用了栈上的 std::array,避免了堆分配,性能良好。
  • 系统调用:

    • 使用了 recvmsgsendmsg,这是传递文件描述符的标准且高效的方式。
    • recvFdWithPayload 中,当缓冲区满时使用 ioctl(..., FIONREAD, ...) 检查剩余数据。这增加了一次系统调用。考虑到这是为了正确处理数据截断的边界情况,这是必要的开销。

4. 代码安全

  • 缓冲区溢出:

    • recvFdWithPayload 使用了 CMSG_SPACECMSG_LEN 宏来计算控制消息缓冲区大小,这是防止缓冲区溢出的正确做法。
    • msg.msg_controllen 被正确设置为 control_buf 的大小。
  • 资源泄漏:

    • recvFdWithPayload 中,如果检测到 MSG_CTRUNC(控制数据被截断),代码会关闭已接收的文件描述符 received_fd,防止泄漏。这是非常好的安全实践。
    • 测试代码 socket_test.cpp 中,所有的 fork 创建的子进程都会关闭文件描述符并 _exit,父进程也会 waitpid,防止僵尸进程。
  • 输入验证:

    • recvFdWithPayloadsendFdWithPayload 都检查了 socketFd < 0 的情况,防止无效文件描述符导致未定义行为。
  • 类型安全:

    • sendFdWithPayloadiov.iov_base 使用了 const_cast。虽然 sendmsg 的手册页说明对于发送缓冲区,const 修饰是安全的,但 struct iovec 的定义没有 const。这里的 const_cast 是必要的,且逻辑上安全,因为不会通过该指针修改数据。

5. 其他建议

  • 测试覆盖:

    • socket_test.cpp 的测试用例非常全面,覆盖了正常流程、无效 FD、空数据、截断、信号中断、对端关闭等场景。特别是 SignalInterruptionRecovery 测试,验证了 EINTR 的处理,非常棒。
    • 建议增加一个测试用例:发送端发送一个无效的 FD(例如一个已关闭的 FD),检查接收端的行为(虽然接收端通常只收到一个整数,内核不保证该 FD 在接收端有效,但测试这种边界情况是有益的)。实际上 SendInvalidFdHandle 已经测试了发送端传入 9999 这种随机整数的情况,这很好。
  • 头文件包含:

    • libs/linglong/src/linglong/cli/cli.cpp 中移除了 #include <charconv>。如果该文件中不再使用 std::from_chars 等功能,这是正确的清理。

总结

整体代码质量很高,逻辑清晰,错误处理完善,安全性考虑周全(特别是资源泄漏防护)。将 errorString 移至 common 模块有助于复用。Socket 通信模块的实现符合 POSIX 标准,测试覆盖率高。

主要改进点

  1. 统一 SocketData 结构体中成员变量的命名(more_data vs isTruncated)。
  2. 为新增的头文件添加详细的函数注释。

@deepin-ci-robot

Copy link
Copy Markdown
Collaborator

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: ComixHe, dengbo11

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@dengbo11 dengbo11 merged commit 4e1c938 into OpenAtom-Linyaps:master Jan 22, 2026
16 checks passed
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

Successfully merging this pull request may close these issues.

4 participants