[libc-commits] [libc] [libc] Add the sockaddr_in6 type and IN6ADDR_*_INIT macros (PR #201357)
Pavel Labath via libc-commits
libc-commits at lists.llvm.org
Thu Jun 4 05:06:26 PDT 2026
https://github.com/labath updated https://github.com/llvm/llvm-project/pull/201357
>From 812e9a3b57248d9fde1b02b083ffb1756c1882e4 Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Wed, 3 Jun 2026 12:53:18 +0000
Subject: [PATCH 1/4] [libc] Add the sockaddr_in6 type and IN6ADDR_*_INIT
macros
This patch adds struct sockaddr_in6 and the
IN6ADDR_ANY_INIT/IN6ADDR_LOOPBACK_INIT initializer macros. These are
configured to be exported via <netinet/in.h>.
I also added tests for these new features:
- layout and initialization check in test/src/netinet/in_test.cpp
verifying sockaddr_in6 size/member alignment and the in6_addr
initializer macros.
- a smoke test in test/src/sys/socket/linux/bind_test.cpp to verify
binding AF_INET6 to a localhost address. This requires a configured
ipv6 stack, and may need tweaking/skipping if our build infrastructure
does not support it.
Assisted by Gemini.
---
libc/hdr/types/CMakeLists.txt | 9 ++++
libc/hdr/types/struct_sockaddr_in6.h | 27 ++++++++++
libc/include/CMakeLists.txt | 1 +
.../llvm-libc-macros/netinet-in-macros.h | 13 +++++
libc/include/llvm-libc-types/CMakeLists.txt | 10 ++++
.../llvm-libc-types/struct_sockaddr_in6.h | 31 ++++++++++++
libc/include/netinet/in.yaml | 5 ++
libc/test/src/netinet/CMakeLists.txt | 2 +
libc/test/src/netinet/in_test.cpp | 50 +++++++++++++++++++
libc/test/src/sys/socket/linux/CMakeLists.txt | 1 +
libc/test/src/sys/socket/linux/bind_test.cpp | 27 ++++++++++
libc/utils/docgen/netinet/in.yaml | 4 ++
12 files changed, 180 insertions(+)
create mode 100644 libc/hdr/types/struct_sockaddr_in6.h
create mode 100644 libc/include/llvm-libc-types/struct_sockaddr_in6.h
diff --git a/libc/hdr/types/CMakeLists.txt b/libc/hdr/types/CMakeLists.txt
index 47d47cc884e1b..4ca50242131d8 100644
--- a/libc/hdr/types/CMakeLists.txt
+++ b/libc/hdr/types/CMakeLists.txt
@@ -492,6 +492,15 @@ add_proxy_header_library(
libc.include.netinet_in
)
+add_proxy_header_library(
+ struct_sockaddr_in6
+ HDRS
+ struct_sockaddr_in6.h
+ FULL_BUILD_DEPENDS
+ libc.include.llvm-libc-types.struct_sockaddr_in6
+ libc.include.netinet_in
+)
+
add_proxy_header_library(
struct_udphdr
HDRS
diff --git a/libc/hdr/types/struct_sockaddr_in6.h b/libc/hdr/types/struct_sockaddr_in6.h
new file mode 100644
index 0000000000000..0a3a0acb82ea3
--- /dev/null
+++ b/libc/hdr/types/struct_sockaddr_in6.h
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Proxy for struct sockaddr_in6.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_HDR_TYPES_STRUCT_SOCKADDR_IN6_H
+#define LLVM_LIBC_HDR_TYPES_STRUCT_SOCKADDR_IN6_H
+
+#ifdef LIBC_FULL_BUILD
+
+#include "include/llvm-libc-types/struct_sockaddr_in6.h"
+
+#else
+
+#include <netinet/in.h>
+
+#endif // LIBC_FULL_BUILD
+
+#endif // LLVM_LIBC_HDR_TYPES_STRUCT_SOCKADDR_IN6_H
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 190d9df2e0bd7..c783bf3f23887 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -223,6 +223,7 @@ add_header_macro(
.llvm-libc-types.in_port_t
.llvm-libc-types.sa_family_t
.llvm-libc-types.struct_sockaddr_in
+ .llvm-libc-types.struct_sockaddr_in6
.llvm-libc-types.struct_in_addr
.llvm-libc-types.struct_in6_addr
.llvm_libc_common_h
diff --git a/libc/include/llvm-libc-macros/netinet-in-macros.h b/libc/include/llvm-libc-macros/netinet-in-macros.h
index f85f6f5403635..6109140fb0ac5 100644
--- a/libc/include/llvm-libc-macros/netinet-in-macros.h
+++ b/libc/include/llvm-libc-macros/netinet-in-macros.h
@@ -33,6 +33,19 @@
// Not specified by POSIX, added in SVR4
#define INADDR_LOOPBACK __LLVM_LIBC_CAST(static_cast, in_addr_t, 0x7f000001)
+#define IN6ADDR_ANY_INIT \
+ { \
+ { \
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } \
+ } \
+ }
+#define IN6ADDR_LOOPBACK_INIT \
+ { \
+ { \
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } \
+ } \
+ }
+
// The following macros test for special IPv6 addresses. Each macro is of type
// int and takes a single argument of type const struct in6_addr *:
// https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/netinet_in.h.html
diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index 5586eff88ef6d..e71f85f8b4533 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -200,6 +200,16 @@ add_header(sa_family_t HDR sa_family_t.h)
add_header(socklen_t HDR socklen_t.h)
add_header(struct_sockaddr HDR struct_sockaddr.h DEPENDS .sa_family_t)
add_header(struct_sockaddr_in HDR struct_sockaddr_in.h DEPENDS .in_port_t .sa_family_t .struct_in_addr)
+add_header(
+ struct_sockaddr_in6
+ HDR
+ struct_sockaddr_in6.h
+ DEPENDS
+ .in_port_t
+ .sa_family_t
+ .struct_in6_addr
+ libc.include.llvm-libc-macros.stdint_macros
+)
add_header(struct_sockaddr_storage HDR struct_sockaddr_storage.h DEPENDS .sa_family_t)
add_header(struct_sockaddr_un HDR struct_sockaddr_un.h DEPENDS .sa_family_t)
add_header(struct_iovec HDR struct_iovec.h DEPENDS .size_t)
diff --git a/libc/include/llvm-libc-types/struct_sockaddr_in6.h b/libc/include/llvm-libc-types/struct_sockaddr_in6.h
new file mode 100644
index 0000000000000..5c5cfb38a6ac3
--- /dev/null
+++ b/libc/include/llvm-libc-types/struct_sockaddr_in6.h
@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Definition of struct sockaddr_in6. This is the sockaddr specialization for
+/// AF_INET6 sockets, as defined by posix.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_TYPES_STRUCT_SOCKADDR_IN6_H
+#define LLVM_LIBC_TYPES_STRUCT_SOCKADDR_IN6_H
+
+#include "../llvm-libc-macros/stdint-macros.h"
+#include "in_port_t.h"
+#include "sa_family_t.h"
+#include "struct_in6_addr.h"
+
+struct __attribute__((may_alias)) sockaddr_in6 {
+ sa_family_t sin6_family;
+ in_port_t sin6_port;
+ uint32_t sin6_flowinfo;
+ struct in6_addr sin6_addr;
+ uint32_t sin6_scope_id;
+};
+
+#endif // LLVM_LIBC_TYPES_STRUCT_SOCKADDR_IN6_H
diff --git a/libc/include/netinet/in.yaml b/libc/include/netinet/in.yaml
index 26e3a7c037c60..0ecdc7e568955 100644
--- a/libc/include/netinet/in.yaml
+++ b/libc/include/netinet/in.yaml
@@ -14,6 +14,10 @@ macros:
macro_header: netinet-in-macros.h
- macro_name: IPPROTO_RAW
macro_header: netinet-in-macros.h
+ - macro_name: IN6ADDR_ANY_INIT
+ macro_header: netinet-in-macros.h
+ - macro_name: IN6ADDR_LOOPBACK_INIT
+ macro_header: netinet-in-macros.h
- macro_name: INET_ADDRSTRLEN
macro_header: inet-address-macros.h
- macro_name: INET6_ADDRSTRLEN
@@ -23,6 +27,7 @@ types:
- type_name: in_addr_t
- type_name: sa_family_t
- type_name: struct_sockaddr_in
+ - type_name: struct_sockaddr_in6
- type_name: struct_in_addr
- type_name: struct_in6_addr
enums: []
diff --git a/libc/test/src/netinet/CMakeLists.txt b/libc/test/src/netinet/CMakeLists.txt
index 36d37f2dbdf72..c168186b60eeb 100644
--- a/libc/test/src/netinet/CMakeLists.txt
+++ b/libc/test/src/netinet/CMakeLists.txt
@@ -7,7 +7,9 @@ add_libc_unittest(
SRCS
in_test.cpp
DEPENDS
+ libc.hdr.netinet_in_macros
libc.hdr.types.struct_in6_addr
+ libc.hdr.types.struct_sockaddr_in6
libc.src.arpa.inet.htons
libc.src.arpa.inet.htonl
libc.src.string.memcmp
diff --git a/libc/test/src/netinet/in_test.cpp b/libc/test/src/netinet/in_test.cpp
index ee3a4af0fa53f..a16850b33619c 100644
--- a/libc/test/src/netinet/in_test.cpp
+++ b/libc/test/src/netinet/in_test.cpp
@@ -16,7 +16,9 @@
#include "src/string/memcmp.h"
#include "test/UnitTest/Test.h"
+#include "hdr/netinet_in_macros.h"
#include "hdr/types/struct_in6_addr.h"
+#include "hdr/types/struct_sockaddr_in6.h"
TEST(LlvmLibcNetinetInTest, In6AddrLayout) {
EXPECT_EQ(sizeof(struct in6_addr), size_t(16));
@@ -52,3 +54,51 @@ TEST(LlvmLibcNetinetInTest, In6AddrLayout) {
16),
0);
}
+
+TEST(LlvmLibcNetinetInTest, IN6AddrInitMacros) {
+ struct in6_addr any = IN6ADDR_ANY_INIT;
+ const uint8_t ANY_CONTENT[16] = {0};
+ EXPECT_EQ(LIBC_NAMESPACE::memcmp(&any, ANY_CONTENT, 16), 0);
+ EXPECT_TRUE(IN6_IS_ADDR_UNSPECIFIED(&any));
+
+ struct in6_addr loopback = IN6ADDR_LOOPBACK_INIT;
+ const uint8_t LOOPBACK_CONTENT[16] = {0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1};
+ EXPECT_EQ(LIBC_NAMESPACE::memcmp(&loopback, LOOPBACK_CONTENT, 16), 0);
+ EXPECT_TRUE(IN6_IS_ADDR_LOOPBACK(&loopback));
+}
+
+TEST(LlvmLibcNetinetInTest, SockaddrIn6Layout) {
+ EXPECT_EQ(sizeof(struct sockaddr_in6), static_cast<size_t>(28));
+
+ struct sockaddr_in6 addr = {};
+ addr.sin6_family = 1;
+ addr.sin6_flowinfo = 3;
+ addr.sin6_scope_id = 4;
+ // The port and address are in network byte order.
+ addr.sin6_port = (LIBC_NAMESPACE::htons)(2);
+ addr.sin6_addr.s6_addr[0] = 0xab;
+ addr.sin6_addr.s6_addr[15] = 0xba;
+
+ const uint8_t CONTENT[] = {
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ 1, 0, // sin6_family
+#else
+ 0, 1, // sin6_family
+#endif
+ 0, 2, // sin6_port
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ 3, 0, 0, 0, // sin6_flowinfo
+#else
+ 0, 0, 0, 3, // sin6_flowinfo
+#endif
+ 0xab, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xba, // sin6_addr
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ 4, 0, 0, 0, // sin6_scope_id
+#else
+ 0, 0, 0, 4, // sin6_scope_id
+#endif
+ };
+
+ EXPECT_EQ(LIBC_NAMESPACE::memcmp(&addr, CONTENT, sizeof(CONTENT)), 0);
+}
diff --git a/libc/test/src/sys/socket/linux/CMakeLists.txt b/libc/test/src/sys/socket/linux/CMakeLists.txt
index bcda617c4b28d..be81d00db9447 100644
--- a/libc/test/src/sys/socket/linux/CMakeLists.txt
+++ b/libc/test/src/sys/socket/linux/CMakeLists.txt
@@ -42,6 +42,7 @@ add_libc_unittest(
libc.hdr.netinet_in_macros
libc.hdr.sys_socket_macros
libc.hdr.types.struct_sockaddr_in
+ libc.hdr.types.struct_sockaddr_in6
libc.hdr.types.struct_sockaddr_un
libc.src.arpa.inet.htonl
libc.src.errno.errno
diff --git a/libc/test/src/sys/socket/linux/bind_test.cpp b/libc/test/src/sys/socket/linux/bind_test.cpp
index 9a459a54ae7ee..271ddba36a026 100644
--- a/libc/test/src/sys/socket/linux/bind_test.cpp
+++ b/libc/test/src/sys/socket/linux/bind_test.cpp
@@ -21,6 +21,7 @@
#include "hdr/netinet_in_macros.h"
#include "hdr/sys_socket_macros.h"
#include "hdr/types/struct_sockaddr_in.h"
+#include "hdr/types/struct_sockaddr_in6.h"
#include "hdr/types/struct_sockaddr_un.h"
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
@@ -75,3 +76,29 @@ TEST_F(LlvmLibcBindTest, BindInetSocket) {
EXPECT_NE(my_addr.sin_port, static_cast<in_port_t>(0));
EXPECT_EQ(my_addr.sin_addr.s_addr, (LIBC_NAMESPACE::htonl)(INADDR_LOOPBACK));
}
+
+TEST_F(LlvmLibcBindTest, BindInet6Socket) {
+ int sock = LIBC_NAMESPACE::socket(AF_INET6, SOCK_DGRAM, 0);
+ ASSERT_GE(sock, 0);
+ ASSERT_ERRNO_SUCCESS();
+ LIBC_NAMESPACE::cpp::scope_exit close_sock(
+ [&] { ASSERT_THAT(LIBC_NAMESPACE::close(sock), Succeeds(0)); });
+
+ struct sockaddr_in6 my_addr = {};
+ my_addr.sin6_family = AF_INET6;
+ my_addr.sin6_addr = IN6ADDR_LOOPBACK_INIT;
+
+ ASSERT_THAT(
+ LIBC_NAMESPACE::bind(sock, reinterpret_cast<struct sockaddr *>(&my_addr),
+ sizeof(struct sockaddr_in6)),
+ Succeeds(0));
+
+ my_addr = {};
+ socklen_t len = sizeof(my_addr);
+ ASSERT_THAT(LIBC_NAMESPACE::getsockname(
+ sock, reinterpret_cast<struct sockaddr *>(&my_addr), &len),
+ Succeeds(0));
+ ASSERT_EQ(len, static_cast<socklen_t>(sizeof(struct sockaddr_in6)));
+ EXPECT_EQ(my_addr.sin6_family, static_cast<sa_family_t>(AF_INET6));
+ EXPECT_NE(my_addr.sin6_port, static_cast<in_port_t>(0));
+}
diff --git a/libc/utils/docgen/netinet/in.yaml b/libc/utils/docgen/netinet/in.yaml
index 215451858dc15..8d47a39b0e6de 100644
--- a/libc/utils/docgen/netinet/in.yaml
+++ b/libc/utils/docgen/netinet/in.yaml
@@ -17,6 +17,10 @@ macros:
in-latest-posix: ''
INADDR_LOOPBACK:
c-definition: ''
+ IN6ADDR_ANY_INIT:
+ in-latest-posix: ''
+ IN6ADDR_LOOPBACK_INIT:
+ in-latest-posix: ''
INET6_ADDRSTRLEN:
in-latest-posix: ''
INET_ADDRSTRLEN:
>From fc70dd5d75c3ba05be1e83a072d786674fce1330 Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Wed, 3 Jun 2026 18:33:14 +0200
Subject: [PATCH 2/4] offsetof
---
libc/test/src/netinet/in_test.cpp | 36 +++++--------------------------
1 file changed, 5 insertions(+), 31 deletions(-)
diff --git a/libc/test/src/netinet/in_test.cpp b/libc/test/src/netinet/in_test.cpp
index a16850b33619c..5fc956f54bca9 100644
--- a/libc/test/src/netinet/in_test.cpp
+++ b/libc/test/src/netinet/in_test.cpp
@@ -69,36 +69,10 @@ TEST(LlvmLibcNetinetInTest, IN6AddrInitMacros) {
}
TEST(LlvmLibcNetinetInTest, SockaddrIn6Layout) {
+ EXPECT_EQ(offsetof(struct sockaddr_in6, sin6_family), static_cast<size_t>(0));
+ EXPECT_EQ(offsetof(struct sockaddr_in6, sin6_port), static_cast<size_t>(2));
+ EXPECT_EQ(offsetof(struct sockaddr_in6, sin6_flowinfo), static_cast<size_t>(4));
+ EXPECT_EQ(offsetof(struct sockaddr_in6, sin6_addr), static_cast<size_t>(8));
+ EXPECT_EQ(offsetof(struct sockaddr_in6, sin6_scope_id), static_cast<size_t>(24));
EXPECT_EQ(sizeof(struct sockaddr_in6), static_cast<size_t>(28));
-
- struct sockaddr_in6 addr = {};
- addr.sin6_family = 1;
- addr.sin6_flowinfo = 3;
- addr.sin6_scope_id = 4;
- // The port and address are in network byte order.
- addr.sin6_port = (LIBC_NAMESPACE::htons)(2);
- addr.sin6_addr.s6_addr[0] = 0xab;
- addr.sin6_addr.s6_addr[15] = 0xba;
-
- const uint8_t CONTENT[] = {
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
- 1, 0, // sin6_family
-#else
- 0, 1, // sin6_family
-#endif
- 0, 2, // sin6_port
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
- 3, 0, 0, 0, // sin6_flowinfo
-#else
- 0, 0, 0, 3, // sin6_flowinfo
-#endif
- 0xab, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xba, // sin6_addr
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
- 4, 0, 0, 0, // sin6_scope_id
-#else
- 0, 0, 0, 4, // sin6_scope_id
-#endif
- };
-
- EXPECT_EQ(LIBC_NAMESPACE::memcmp(&addr, CONTENT, sizeof(CONTENT)), 0);
}
>From b16ff5cb577cfb5529cd761e71909a8c3ebad14c Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Wed, 3 Jun 2026 20:37:00 +0200
Subject: [PATCH 3/4] format
---
libc/test/src/netinet/in_test.cpp | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/libc/test/src/netinet/in_test.cpp b/libc/test/src/netinet/in_test.cpp
index 5fc956f54bca9..2175c2dac601f 100644
--- a/libc/test/src/netinet/in_test.cpp
+++ b/libc/test/src/netinet/in_test.cpp
@@ -71,8 +71,10 @@ TEST(LlvmLibcNetinetInTest, IN6AddrInitMacros) {
TEST(LlvmLibcNetinetInTest, SockaddrIn6Layout) {
EXPECT_EQ(offsetof(struct sockaddr_in6, sin6_family), static_cast<size_t>(0));
EXPECT_EQ(offsetof(struct sockaddr_in6, sin6_port), static_cast<size_t>(2));
- EXPECT_EQ(offsetof(struct sockaddr_in6, sin6_flowinfo), static_cast<size_t>(4));
+ EXPECT_EQ(offsetof(struct sockaddr_in6, sin6_flowinfo),
+ static_cast<size_t>(4));
EXPECT_EQ(offsetof(struct sockaddr_in6, sin6_addr), static_cast<size_t>(8));
- EXPECT_EQ(offsetof(struct sockaddr_in6, sin6_scope_id), static_cast<size_t>(24));
+ EXPECT_EQ(offsetof(struct sockaddr_in6, sin6_scope_id),
+ static_cast<size_t>(24));
EXPECT_EQ(sizeof(struct sockaddr_in6), static_cast<size_t>(28));
}
>From dfd1412d5f7aeb97d3a8ad434b2483f37ef61d3f Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Thu, 4 Jun 2026 12:05:55 +0000
Subject: [PATCH 4/4] accept EADDRNOTAVAIL
---
libc/test/src/sys/socket/linux/bind_test.cpp | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/libc/test/src/sys/socket/linux/bind_test.cpp b/libc/test/src/sys/socket/linux/bind_test.cpp
index 271ddba36a026..af2b855c7e6c1 100644
--- a/libc/test/src/sys/socket/linux/bind_test.cpp
+++ b/libc/test/src/sys/socket/linux/bind_test.cpp
@@ -88,10 +88,13 @@ TEST_F(LlvmLibcBindTest, BindInet6Socket) {
my_addr.sin6_family = AF_INET6;
my_addr.sin6_addr = IN6ADDR_LOOPBACK_INIT;
- ASSERT_THAT(
+ int result =
LIBC_NAMESPACE::bind(sock, reinterpret_cast<struct sockaddr *>(&my_addr),
- sizeof(struct sockaddr_in6)),
- Succeeds(0));
+ sizeof(struct sockaddr_in6));
+ if (result == -1) {
+ ASSERT_ERRNO_EQ(EADDRNOTAVAIL); // Ipv6 not available on this host.
+ return;
+ }
my_addr = {};
socklen_t len = sizeof(my_addr);
More information about the libc-commits
mailing list