[libc-commits] [libc] [libc] Implement connect(2) on linux (PR #189668)
Pavel Labath via libc-commits
libc-commits at lists.llvm.org
Thu Apr 2 06:15:13 PDT 2026
https://github.com/labath updated https://github.com/llvm/llvm-project/pull/189668
>From f0a5a7a507f24162c43bc08687fd587b6e5d9e21 Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Tue, 31 Mar 2026 15:30:39 +0200
Subject: [PATCH 1/2] [libc] Implement connect(2) on linux
I'm using the new syscall wrapper framework, and enabling the entry
point for x86_64, aarch64 and riscv. The associated test currently only
checks for the error code. Once we have listen&accept (which I'm
probably going to tackle next), we can test that the two can talk to
each other.
---
libc/config/linux/aarch64/entrypoints.txt | 1 +
libc/config/linux/riscv/entrypoints.txt | 1 +
libc/config/linux/x86_64/entrypoints.txt | 1 +
.../linux/syscall_wrappers/CMakeLists.txt | 15 ++++
.../OSUtil/linux/syscall_wrappers/connect.h | 48 +++++++++++++
libc/src/sys/socket/CMakeLists.txt | 7 ++
libc/src/sys/socket/connect.h | 23 +++++++
libc/src/sys/socket/linux/CMakeLists.txt | 14 ++++
libc/src/sys/socket/linux/connect.cpp | 31 +++++++++
libc/test/src/sys/socket/linux/CMakeLists.txt | 20 ++++++
.../src/sys/socket/linux/connect_test.cpp | 68 +++++++++++++++++++
11 files changed, 229 insertions(+)
create mode 100644 libc/src/__support/OSUtil/linux/syscall_wrappers/connect.h
create mode 100644 libc/src/sys/socket/connect.h
create mode 100644 libc/src/sys/socket/linux/connect.cpp
create mode 100644 libc/test/src/sys/socket/linux/connect_test.cpp
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index e683da7300e38..83088456fb4ac 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1209,6 +1209,7 @@ if(LLVM_LIBC_FULL_BUILD)
# sys/socket.h entrypoints
libc.src.sys.socket.bind
+ libc.src.sys.socket.connect
libc.src.sys.socket.socket
)
endif()
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 5782acb727ee2..1f7180d23a840 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -1343,6 +1343,7 @@ if(LLVM_LIBC_FULL_BUILD)
# sys/socket.h entrypoints
libc.src.sys.socket.bind
+ libc.src.sys.socket.connect
libc.src.sys.socket.socket
libc.src.sys.socket.socketpair
libc.src.sys.socket.send
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 90a0dade5435a..20434fb9e838f 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1414,6 +1414,7 @@ if(LLVM_LIBC_FULL_BUILD)
# sys/socket.h entrypoints
libc.src.sys.socket.socket
libc.src.sys.socket.bind
+ libc.src.sys.socket.connect
libc.src.sys.socket.socketpair
libc.src.sys.socket.send
libc.src.sys.socket.sendto
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
index 50e31eba161d6..7f28ab7829d66 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
@@ -23,6 +23,21 @@ add_header_library(
libc.include.sys_syscall
)
+add_header_library(
+ connect
+ HDRS
+ connect.h
+ DEPENDS
+ libc.src.__support.OSUtil.linux.syscall_wrappers.connect
+ libc.src.__support.common
+ libc.src.__support.error_or
+ libc.src.__support.libc_errno
+ libc.src.__support.macros.config
+ libc.hdr.types.socklen_t
+ libc.hdr.types.struct_sockaddr
+ libc.include.sys_syscall
+)
+
add_header_library(
read
HDRS
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/connect.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/connect.h
new file mode 100644
index 0000000000000..6974546630b00
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/connect.h
@@ -0,0 +1,48 @@
+//===-- Implementation header for connect -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_CONNECT_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_CONNECT_H
+
+#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl
+#include "src/__support/common.h"
+#include "src/__support/error_or.h"
+#include "src/__support/macros/config.h"
+
+#include "hdr/types/socklen_t.h"
+#include "hdr/types/struct_sockaddr.h"
+#include <linux/net.h> // For SYS_SOCKET socketcall number.
+#include <sys/syscall.h> // For syscall numbers
+
+namespace LIBC_NAMESPACE_DECL {
+namespace linux_syscalls {
+
+LIBC_INLINE ErrorOr<int> connect(int sockfd, const struct sockaddr *addr,
+ socklen_t addrlen) {
+#ifdef SYS_connect
+ int ret =
+ LIBC_NAMESPACE::syscall_impl<int>(SYS_connect, sockfd, addr, addrlen);
+#elif defined(SYS_socketcall)
+ unsigned long sockcall_args[3] = {static_cast<unsigned long>(sockfd),
+ reinterpret_cast<unsigned long>(addr),
+ static_cast<unsigned long>(addrlen)};
+ int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_socketcall, SYS_CONNECT,
+ sockcall_args);
+#else
+#error "socket and socketcall syscalls unavailable for this platform."
+#endif
+
+ if (ret < 0)
+ return Error(-static_cast<int>(ret));
+ return ret;
+}
+
+} // namespace linux_syscalls
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_CONNECT_H
diff --git a/libc/src/sys/socket/CMakeLists.txt b/libc/src/sys/socket/CMakeLists.txt
index 5c58e16ef7b31..5d9e2ff2d2f76 100644
--- a/libc/src/sys/socket/CMakeLists.txt
+++ b/libc/src/sys/socket/CMakeLists.txt
@@ -16,6 +16,13 @@ add_entrypoint_object(
.${LIBC_TARGET_OS}.bind
)
+add_entrypoint_object(
+ connect
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.connect
+)
+
add_entrypoint_object(
socketpair
ALIAS
diff --git a/libc/src/sys/socket/connect.h b/libc/src/sys/socket/connect.h
new file mode 100644
index 0000000000000..8e338103c4a21
--- /dev/null
+++ b/libc/src/sys/socket/connect.h
@@ -0,0 +1,23 @@
+//===-- Implementation header for connect -----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SYS_SOCKET_CONNECT_H
+#define LLVM_LIBC_SRC_SYS_SOCKET_CONNECT_H
+
+#include "src/__support/macros/config.h"
+
+#include "hdr/types/socklen_t.h"
+#include "hdr/types/struct_sockaddr.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SYS_SOCKET_CONNECT_H
diff --git a/libc/src/sys/socket/linux/CMakeLists.txt b/libc/src/sys/socket/linux/CMakeLists.txt
index e1226aaad381f..ad62dc83226cd 100644
--- a/libc/src/sys/socket/linux/CMakeLists.txt
+++ b/libc/src/sys/socket/linux/CMakeLists.txt
@@ -24,6 +24,20 @@ add_entrypoint_object(
libc.src.errno.errno
)
+add_entrypoint_object(
+ connect
+ SRCS
+ connect.cpp
+ HDRS
+ ../socket.h
+ DEPENDS
+ libc.include.sys_socket
+ libc.src.__support.OSUtil.osutil
+ libc.hdr.types.struct_sockaddr
+ libc.hdr.types.socklen_t
+ libc.src.errno.errno
+)
+
add_entrypoint_object(
socketpair
SRCS
diff --git a/libc/src/sys/socket/linux/connect.cpp b/libc/src/sys/socket/linux/connect.cpp
new file mode 100644
index 0000000000000..d7d46cda48b0e
--- /dev/null
+++ b/libc/src/sys/socket/linux/connect.cpp
@@ -0,0 +1,31 @@
+//===-- Linux implementation of connect -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/sys/socket/connect.h"
+
+#include "hdr/types/socklen_t.h"
+#include "hdr/types/struct_sockaddr.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/connect.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, connect,
+ (int sockfd, const struct sockaddr *addr,
+ socklen_t addrlen)) {
+ auto result = linux_syscalls::connect(sockfd, addr, addrlen);
+ if (!result.has_value()) {
+ libc_errno = result.error();
+ return -1;
+ }
+
+ return result.value();
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/sys/socket/linux/CMakeLists.txt b/libc/test/src/sys/socket/linux/CMakeLists.txt
index 1ff814029b330..95c0d622bdcdd 100644
--- a/libc/test/src/sys/socket/linux/CMakeLists.txt
+++ b/libc/test/src/sys/socket/linux/CMakeLists.txt
@@ -34,6 +34,26 @@ add_libc_unittest(
libc.test.UnitTest.ErrnoSetterMatcher
)
+add_libc_unittest(
+ connect_test
+ SUITE
+ libc_sys_socket_unittests
+ SRCS
+ connect_test.cpp
+ DEPENDS
+ libc.include.sys_socket
+ libc.hdr.sys_socket_macros
+ libc.hdr.types.struct_sockaddr_un
+ libc.src.errno.errno
+ libc.src.sys.socket.socket
+ libc.src.sys.socket.bind
+ libc.src.sys.socket.connect
+ libc.src.stdio.remove
+ libc.src.unistd.close
+ libc.test.UnitTest.ErrnoCheckingTest
+ libc.test.UnitTest.ErrnoSetterMatcher
+)
+
add_libc_unittest(
socketpair_test
SUITE
diff --git a/libc/test/src/sys/socket/linux/connect_test.cpp b/libc/test/src/sys/socket/linux/connect_test.cpp
new file mode 100644
index 0000000000000..05501eb7dd560
--- /dev/null
+++ b/libc/test/src/sys/socket/linux/connect_test.cpp
@@ -0,0 +1,68 @@
+//===-- Unittests for connect ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "hdr/sys_socket_macros.h"
+#include "hdr/types/struct_sockaddr_un.h"
+#include "src/sys/socket/bind.h"
+#include "src/sys/socket/connect.h"
+#include "src/sys/socket/socket.h"
+
+#include "src/stdio/remove.h"
+#include "src/unistd/close.h"
+
+#include "test/UnitTest/ErrnoCheckingTest.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+#include "test/UnitTest/Test.h"
+
+using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
+using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
+using LlvmLibcConnectTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+
+TEST_F(LlvmLibcConnectTest, ConnectLocalSocket) {
+
+ const char *FILENAME = "connect_file.test";
+ auto SOCK_PATH = libc_make_test_file_path(FILENAME);
+
+ int sock1 = LIBC_NAMESPACE::socket(AF_UNIX, SOCK_STREAM, 0);
+ ASSERT_GE(sock1, 0);
+ ASSERT_ERRNO_SUCCESS();
+
+ struct sockaddr_un my_addr;
+
+ my_addr.sun_family = AF_UNIX;
+ unsigned int i = 0;
+ for (;
+ SOCK_PATH[i] != '\0' && (i < sizeof(sockaddr_un) - sizeof(sa_family_t));
+ ++i)
+ my_addr.sun_path[i] = SOCK_PATH[i];
+
+ // It's important that the path fits in the struct, if it doesn't then we
+ // can't try to bind to the file.
+ ASSERT_LT(
+ i, static_cast<unsigned int>(sizeof(sockaddr_un) - sizeof(sa_family_t)));
+ my_addr.sun_path[i] = '\0';
+
+ ASSERT_THAT(
+ LIBC_NAMESPACE::bind(sock1, reinterpret_cast<struct sockaddr *>(&my_addr),
+ sizeof(struct sockaddr_un)),
+ Succeeds(0));
+
+ int sock2 = LIBC_NAMESPACE::socket(AF_UNIX, SOCK_STREAM, 0);
+ ASSERT_GE(sock2, 0);
+ ASSERT_ERRNO_SUCCESS();
+
+ ASSERT_THAT(
+ LIBC_NAMESPACE::connect(sock2,
+ reinterpret_cast<struct sockaddr *>(&my_addr),
+ sizeof(struct sockaddr_un)),
+ Fails(ECONNREFUSED)); // Because the other side is not listen()ing.
+
+ ASSERT_THAT(LIBC_NAMESPACE::close(sock1), Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::close(sock2), Succeeds(0));
+ ASSERT_THAT(LIBC_NAMESPACE::remove(SOCK_PATH), Succeeds(0));
+}
>From c6d8f0a7e030ffd698ef2522db9b535c640c0ce1 Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Thu, 2 Apr 2026 15:14:42 +0200
Subject: [PATCH 2/2] fix HDRS value
---
libc/src/sys/socket/linux/CMakeLists.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libc/src/sys/socket/linux/CMakeLists.txt b/libc/src/sys/socket/linux/CMakeLists.txt
index ad62dc83226cd..5be93e252cf52 100644
--- a/libc/src/sys/socket/linux/CMakeLists.txt
+++ b/libc/src/sys/socket/linux/CMakeLists.txt
@@ -29,7 +29,7 @@ add_entrypoint_object(
SRCS
connect.cpp
HDRS
- ../socket.h
+ ../connect.h
DEPENDS
libc.include.sys_socket
libc.src.__support.OSUtil.osutil
More information about the libc-commits
mailing list