[libc-commits] [libc] [libc] Add the MSG_ flags (PR #194375)

Pavel Labath via libc-commits libc-commits at lists.llvm.org
Mon Apr 27 06:54:05 PDT 2026


https://github.com/labath updated https://github.com/llvm/llvm-project/pull/194375

>From 8fc3598b3271c56d08f22935c86d773b560d1101 Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Mon, 27 Apr 2026 13:08:09 +0000
Subject: [PATCH] [libc] Add the MSG_ flags

I've included all of the flags defined on linux, even those not
documented in POSIX (or the manpage). I've also added tests to exercise
the flags, for cases where this can be done with domain sockets.
---
 .../linux/sys-socket-macros.h                 | 23 +++++++
 libc/test/src/sys/socket/linux/CMakeLists.txt |  3 +
 .../src/sys/socket/linux/send_recv_test.cpp   | 44 +++++++++++-
 .../sys/socket/linux/sendmsg_recvmsg_test.cpp | 67 +++++++++++++++++++
 4 files changed, 135 insertions(+), 2 deletions(-)

diff --git a/libc/include/llvm-libc-macros/linux/sys-socket-macros.h b/libc/include/llvm-libc-macros/linux/sys-socket-macros.h
index 0d4460df0196b..1c6ae9f394f63 100644
--- a/libc/include/llvm-libc-macros/linux/sys-socket-macros.h
+++ b/libc/include/llvm-libc-macros/linux/sys-socket-macros.h
@@ -52,6 +52,29 @@
 
 #define SCM_RIGHTS 1
 
+#define MSG_OOB 0x01
+#define MSG_PEEK 0x02
+#define MSG_DONTROUTE 0x04
+#define MSG_CTRUNC 0x08
+#define MSG_PROXY 0x10
+#define MSG_TRUNC 0x20
+#define MSG_DONTWAIT 0x40
+#define MSG_EOR 0x80
+#define MSG_WAITALL 0x100
+#define MSG_FIN 0x200
+#define MSG_SYN 0x400
+#define MSG_CONFIRM 0x800
+#define MSG_RST 0x1000
+#define MSG_ERRQUEUE 0x2000
+#define MSG_NOSIGNAL 0x4000
+#define MSG_MORE 0x8000
+#define MSG_WAITFORONE 0x10000
+#define MSG_BATCH 0x40000
+#define MSG_SOCK_DEVMEM 0x2000000
+#define MSG_ZEROCOPY 0x4000000
+#define MSG_FASTOPEN 0x20000000
+#define MSG_CMSG_CLOEXEC 0x40000000
+
 #define CMSG_ALIGN(len) (((len) + sizeof(size_t) - 1) & ~(sizeof(size_t) - 1))
 #define CMSG_LEN(len) (sizeof(struct cmsghdr) + (len))
 #define CMSG_SPACE(len) (sizeof(struct cmsghdr) + CMSG_ALIGN(len))
diff --git a/libc/test/src/sys/socket/linux/CMakeLists.txt b/libc/test/src/sys/socket/linux/CMakeLists.txt
index ef88e7e6b9499..85b570e82af04 100644
--- a/libc/test/src/sys/socket/linux/CMakeLists.txt
+++ b/libc/test/src/sys/socket/linux/CMakeLists.txt
@@ -126,7 +126,9 @@ add_libc_unittest(
     send_recv_test.cpp
   DEPENDS
     libc.include.sys_socket
+    libc.hdr.sys_socket_macros
     libc.src.errno.errno
+    libc.src.string.memset
     libc.src.sys.socket.socketpair
     libc.src.sys.socket.send
     libc.src.sys.socket.recv
@@ -162,6 +164,7 @@ add_libc_unittest(
     libc.include.sys_socket
     libc.hdr.types.struct_cmsghdr
     libc.src.errno.errno
+    libc.src.fcntl.fcntl
     libc.src.string.memcpy
     libc.src.string.memset
     libc.src.sys.socket.getsockopt
diff --git a/libc/test/src/sys/socket/linux/send_recv_test.cpp b/libc/test/src/sys/socket/linux/send_recv_test.cpp
index a5a9b29228ece..bf1ed2ce5e9dc 100644
--- a/libc/test/src/sys/socket/linux/send_recv_test.cpp
+++ b/libc/test/src/sys/socket/linux/send_recv_test.cpp
@@ -10,14 +10,14 @@
 #include "src/sys/socket/send.h"
 #include "src/sys/socket/socketpair.h"
 
+#include "src/string/memset.h"
 #include "src/unistd/close.h"
 
+#include "hdr/sys_socket_macros.h"
 #include "test/UnitTest/ErrnoCheckingTest.h"
 #include "test/UnitTest/ErrnoSetterMatcher.h"
 #include "test/UnitTest/Test.h"
 
-#include <sys/socket.h> // For AF_UNIX and SOCK_DGRAM
-
 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
 using LlvmLibcSendRecvTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
@@ -46,6 +46,46 @@ TEST_F(LlvmLibcSendRecvTest, SucceedsWithSocketPair) {
   ASSERT_THAT(LIBC_NAMESPACE::close(sockpair[1]), Succeeds(0));
 }
 
+TEST_F(LlvmLibcSendRecvTest, MsgFlagsTest) {
+  int sockpair[2] = {0, 0};
+
+  ASSERT_THAT(LIBC_NAMESPACE::socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockpair),
+              Succeeds(0));
+
+  char buffer[256];
+
+  // MSG_DONTWAIT on an empty socket returns EAGAIN
+  ASSERT_THAT(
+      LIBC_NAMESPACE::recv(sockpair[1], buffer, sizeof(buffer), MSG_DONTWAIT),
+      Fails<ssize_t>(EAGAIN));
+
+  const char TEST_MESSAGE[] = "this is a long message";
+  const size_t MESSAGE_LEN = sizeof(TEST_MESSAGE);
+
+  ASSERT_THAT(LIBC_NAMESPACE::send(sockpair[0], TEST_MESSAGE, MESSAGE_LEN, 0),
+              Succeeds(static_cast<ssize_t>(MESSAGE_LEN)));
+
+  // MSG_PEEK does not remove the message from the socket
+  ASSERT_THAT(
+      LIBC_NAMESPACE::recv(sockpair[1], buffer, sizeof(buffer), MSG_PEEK),
+      Succeeds(static_cast<ssize_t>(MESSAGE_LEN)));
+  ASSERT_STREQ(buffer, TEST_MESSAGE);
+  LIBC_NAMESPACE::memset(buffer, 0, sizeof(buffer));
+
+  // Read the message again, but use a smaller buffer to test MSG_TRUNC. Return
+  // value should be real length.
+  ASSERT_THAT(LIBC_NAMESPACE::recv(sockpair[1], buffer, 5, MSG_TRUNC),
+              Succeeds(static_cast<ssize_t>(MESSAGE_LEN)));
+  ASSERT_STREQ(buffer, "this ");
+
+  // Sending with MSG_NOSIGNAL to a closed socket should fail with EPIPE
+  ASSERT_THAT(LIBC_NAMESPACE::close(sockpair[1]), Succeeds(0));
+  ASSERT_THAT(LIBC_NAMESPACE::send(sockpair[0], "x", 1, MSG_NOSIGNAL),
+              Fails<ssize_t>(EPIPE));
+
+  ASSERT_THAT(LIBC_NAMESPACE::close(sockpair[0]), Succeeds(0));
+}
+
 TEST_F(LlvmLibcSendRecvTest, SendFails) {
   const char TEST_MESSAGE[] = "connection terminated";
   const size_t MESSAGE_LEN = sizeof(TEST_MESSAGE);
diff --git a/libc/test/src/sys/socket/linux/sendmsg_recvmsg_test.cpp b/libc/test/src/sys/socket/linux/sendmsg_recvmsg_test.cpp
index c313938652cc7..eb99dd8dbeaca 100644
--- a/libc/test/src/sys/socket/linux/sendmsg_recvmsg_test.cpp
+++ b/libc/test/src/sys/socket/linux/sendmsg_recvmsg_test.cpp
@@ -6,9 +6,11 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "hdr/fcntl_macros.h"
 #include "hdr/sys_socket_macros.h"
 #include "hdr/types/struct_cmsghdr.h"
 #include "include/llvm-libc-macros/linux/sys-socket-macros.h"
+#include "src/fcntl/fcntl.h"
 #include "src/string/memcpy.h"
 #include "src/string/memset.h"
 #include "src/sys/socket/getsockopt.h"
@@ -196,6 +198,71 @@ TEST_F(LlvmLibcSendMsgRecvMsgTest, SendAndReceiveFileDescriptor) {
   ASSERT_THAT(LIBC_NAMESPACE::close(new_fd), Succeeds(0));
 }
 
+TEST_F(LlvmLibcSendMsgRecvMsgTest, MsgCmsgCloexec) {
+  int sockpair[2] = {0, 0};
+
+  ASSERT_THAT(LIBC_NAMESPACE::socketpair(AF_UNIX, SOCK_STREAM, 0, sockpair),
+              Succeeds(0));
+
+  struct iovec iov;
+  iov.iov_base = reinterpret_cast<void *>(const_cast<char *>("x"));
+  iov.iov_len = 1;
+
+  char control_buf[CMSG_SPACE(sizeof(int))] = {};
+
+  struct msghdr msg;
+  msg.msg_name = nullptr;
+  msg.msg_namelen = 0;
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+  msg.msg_flags = 0;
+  msg.msg_control = control_buf;
+  msg.msg_controllen = CMSG_LEN(sizeof(int));
+
+  struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
+  cmsg->cmsg_level = SOL_SOCKET;
+  cmsg->cmsg_type = SCM_RIGHTS;
+  cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+  LIBC_NAMESPACE::memcpy(CMSG_DATA(cmsg), sockpair + 1, sizeof(int));
+
+  ASSERT_THAT(LIBC_NAMESPACE::sendmsg(sockpair[0], &msg, 0),
+              Succeeds(static_cast<ssize_t>(1)));
+
+  char buffer[256];
+
+  iov.iov_base = buffer;
+  iov.iov_len = sizeof(buffer);
+
+  LIBC_NAMESPACE::memset(control_buf, 0, sizeof(control_buf));
+
+  msg.msg_name = nullptr;
+  msg.msg_namelen = 0;
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+  msg.msg_control = control_buf;
+  msg.msg_controllen = sizeof(control_buf);
+  msg.msg_flags = 0;
+
+  // Receive with MSG_CMSG_CLOEXEC
+  ASSERT_THAT(LIBC_NAMESPACE::recvmsg(sockpair[1], &msg, MSG_CMSG_CLOEXEC),
+              Succeeds(static_cast<ssize_t>(1)));
+
+  cmsg = CMSG_FIRSTHDR(&msg);
+  ASSERT_TRUE(cmsg != nullptr);
+
+  int new_fd;
+  LIBC_NAMESPACE::memcpy(&new_fd, CMSG_DATA(cmsg), sizeof(int));
+
+  // Check FD_CLOEXEC
+  int flags = LIBC_NAMESPACE::fcntl(new_fd, F_GETFD);
+  ASSERT_GE(flags, 0);
+  ASSERT_NE(flags & FD_CLOEXEC, 0);
+
+  ASSERT_THAT(LIBC_NAMESPACE::close(sockpair[0]), Succeeds(0));
+  ASSERT_THAT(LIBC_NAMESPACE::close(sockpair[1]), Succeeds(0));
+  ASSERT_THAT(LIBC_NAMESPACE::close(new_fd), Succeeds(0));
+}
+
 TEST_F(LlvmLibcSendMsgRecvMsgTest, SendFails) {
   const char TEST_MESSAGE[] = "connection terminated";
   const size_t MESSAGE_LEN = sizeof(TEST_MESSAGE);



More information about the libc-commits mailing list