[libc-commits] [libc] [libc] Add bind function (PR #74014)

via libc-commits libc-commits at lists.llvm.org
Thu Nov 30 16:42:00 PST 2023


https://github.com/michaelrj-google created https://github.com/llvm/llvm-project/pull/74014

This patch adds the bind function to go with the socket function. It
also cleans up a lot of socket related data structures.


>From b839e06282d22f09fe52f28f6917c365c95c302c Mon Sep 17 00:00:00 2001
From: Michael Jones <michaelrj at google.com>
Date: Thu, 30 Nov 2023 16:39:01 -0800
Subject: [PATCH] [libc] Add bind function

This patch adds the bind function to go with the socket function. It
also cleans up a lot of socket related data structures.
---
 libc/config/linux/api.td                      |  7 ++-
 libc/config/linux/x86_64/entrypoints.txt      |  1 +
 libc/include/CMakeLists.txt                   |  4 +-
 libc/include/llvm-libc-types/CMakeLists.txt   |  2 +
 libc/include/llvm-libc-types/socklen_t.h      | 18 ++++++
 .../include/llvm-libc-types/struct_sockaddr.h | 10 ++--
 .../llvm-libc-types/struct_sockaddr_un.h      | 22 ++++++++
 libc/spec/posix.td                            | 17 +++++-
 libc/src/sys/socket/CMakeLists.txt            |  7 +++
 libc/src/sys/socket/bind.h                    | 20 +++++++
 libc/src/sys/socket/linux/CMakeLists.txt      | 13 +++++
 libc/src/sys/socket/linux/bind.cpp            | 43 +++++++++++++++
 libc/src/sys/socket/linux/socket.cpp          |  4 +-
 libc/test/src/sys/socket/linux/CMakeLists.txt | 16 ++++++
 libc/test/src/sys/socket/linux/bind_test.cpp  | 55 +++++++++++++++++++
 .../test/src/sys/socket/linux/socket_test.cpp |  4 +-
 16 files changed, 231 insertions(+), 12 deletions(-)
 create mode 100644 libc/include/llvm-libc-types/socklen_t.h
 create mode 100644 libc/include/llvm-libc-types/struct_sockaddr_un.h
 create mode 100644 libc/src/sys/socket/bind.h
 create mode 100644 libc/src/sys/socket/linux/bind.cpp
 create mode 100644 libc/test/src/sys/socket/linux/bind_test.cpp

diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td
index 726e58f376eaa76..85f6b59264eb06d 100644
--- a/libc/config/linux/api.td
+++ b/libc/config/linux/api.td
@@ -205,7 +205,12 @@ def SysSelectAPI : PublicAPI<"sys/select.h"> {
 }
 
 def SysSocketAPI : PublicAPI<"sys/socket.h"> {
-  let Types = ["struct sockaddr", "sa_family_t"];
+  let Types = [
+    "sa_family_t",
+    "socklen_t",
+    "struct sockaddr",
+    "struct sockaddr_un",
+  ];
 }
 
 def SysResourceAPI : PublicAPI<"sys/resource.h"> {
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index eb5457678e99091..58a90c1ceaa0372 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -156,6 +156,7 @@ set(TARGET_LIBC_ENTRYPOINTS
 
     # sys/socket.h entrypoints
     libc.src.sys.socket.socket
+    libc.src.sys.socket.bind
 
     # sys/stat.h entrypoints
     libc.src.sys.stat.chmod
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 429c0f1f12866a8..59c6c4a9bb42000 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -417,8 +417,10 @@ add_gen_header(
   DEPENDS
     .llvm_libc_common_h
     .llvm-libc-macros.sys_socket_macros
-    .llvm-libc-types.struct_sockaddr
     .llvm-libc-types.sa_family_t
+    .llvm-libc-types.socklen_t
+    .llvm-libc-types.struct_sockaddr
+    .llvm-libc-types.struct_sockaddr_un
 )
 
 add_gen_header(
diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index 225ad780c4d01f2..500900ffa0bbb05 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -89,6 +89,8 @@ add_header(__getoptargv_t HDR __getoptargv_t.h)
 add_header(wchar_t HDR wchar_t.h)
 add_header(wint_t HDR wint_t.h)
 add_header(sa_family_t HDR sa_family_t.h)
+add_header(socklen_t HDR socklen_t.h)
+add_header(struct_sockaddr_un HDR struct_sockaddr_un.h)
 add_header(struct_sockaddr HDR struct_sockaddr.h)
 add_header(rpc_opcodes_t HDR rpc_opcodes_t.h)
 add_header(ACTION HDR ACTION.h)
diff --git a/libc/include/llvm-libc-types/socklen_t.h b/libc/include/llvm-libc-types/socklen_t.h
new file mode 100644
index 000000000000000..3134a53390e71ed
--- /dev/null
+++ b/libc/include/llvm-libc-types/socklen_t.h
@@ -0,0 +1,18 @@
+//===-- Definition of socklen_t type ------------------------------------===//
+//
+// 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_TYPES_SOCKLEN_T_H__
+#define __LLVM_LIBC_TYPES_SOCKLEN_T_H__
+
+// The posix standard only says of socklen_t that it must be an integer type of
+// width of at least 32 bits. The long type is defined as being at least 32
+// bits, so an unsigned long should be fine.
+
+typedef unsigned long socklen_t;
+
+#endif // __LLVM_LIBC_TYPES_SOCKLEN_T_H__
diff --git a/libc/include/llvm-libc-types/struct_sockaddr.h b/libc/include/llvm-libc-types/struct_sockaddr.h
index 1ef907904ca3ec1..9a6214c7d3e6b9b 100644
--- a/libc/include/llvm-libc-types/struct_sockaddr.h
+++ b/libc/include/llvm-libc-types/struct_sockaddr.h
@@ -1,4 +1,4 @@
-//===-- Definition of struct stat -----------------------------------------===//
+//===-- Definition of struct sockaddr -------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef __LLVM_LIBC_TYPES_STRUCT_STAT_H__
-#define __LLVM_LIBC_TYPES_STRUCT_STAT_H__
+#ifndef __LLVM_LIBC_TYPES_STRUCT_SOCKADDR_H__
+#define __LLVM_LIBC_TYPES_STRUCT_SOCKADDR_H__
 
 #include <llvm-libc-types/sa_family_t.h>
 
@@ -15,7 +15,7 @@ struct sockaddr {
   sa_family_t sa_family;
   // sa_data is a variable length array. It is provided with a length of one
   // here as a placeholder.
-  char sa_data[1];
+  char sa_data[];
 };
 
-#endif // __LLVM_LIBC_TYPES_STRUCT_STAT_H__
+#endif // __LLVM_LIBC_TYPES_STRUCT_SOCKADDR_H__
diff --git a/libc/include/llvm-libc-types/struct_sockaddr_un.h b/libc/include/llvm-libc-types/struct_sockaddr_un.h
new file mode 100644
index 000000000000000..9c3efea279256ec
--- /dev/null
+++ b/libc/include/llvm-libc-types/struct_sockaddr_un.h
@@ -0,0 +1,22 @@
+//===-- Definition of struct sockaddr_un ----------------------------------===//
+//
+// 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_TYPES_STRUCT_SOCKADDR_UN_H__
+#define __LLVM_LIBC_TYPES_STRUCT_SOCKADDR_UN_H__
+
+#include <llvm-libc-types/sa_family_t.h>
+
+// This is the sockaddr specialization for AF_UNIX or AF_LOCAL sockets, as
+// defined by posix.
+
+struct sockaddr_un {
+  sa_family_t sun_family; /* AF_UNIX */
+  char sun_path[108];     /* Pathname */
+};
+
+#endif // __LLVM_LIBC_TYPES_STRUCT_SOCKADDR_UN_H__
diff --git a/libc/spec/posix.td b/libc/spec/posix.td
index c7acf6d25a2d873..7e1cf892135acf9 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -81,9 +81,14 @@ def RestrictedFdSetPtr : RestrictedPtrType<FdSet>;
 
 def GetoptArgvT : NamedType<"__getoptargv_t">;
 
+def SAFamilyType : NamedType<"sa_family_t">;
+def SocklenType : NamedType<"socklen_t">;
+
 def StructSockAddr : NamedType<"struct sockaddr">;
 def StructSockAddrPtr : PtrType<StructSockAddr>;
-def SAFamilyType : NamedType<"sa_family_t">;
+def ConstStructSockAddrPtr : ConstType<StructSockAddrPtr>;
+
+def StructSockAddrUn : NamedType<"struct sockaddr_un">;
 
 def POSIX : StandardSpec<"POSIX"> {
   PtrType CharPtr = PtrType<CharType>;
@@ -1400,7 +1405,10 @@ def POSIX : StandardSpec<"POSIX"> {
         Macro<"SOCK_PACKET">,
       ], // Macros
       [
-        StructSockAddr, SAFamilyType,
+        SAFamilyType,
+        StructSockAddr,
+        StructSockAddrUn,
+        SocklenType,
       ], // Types
       [], // Enumerations
       [
@@ -1409,6 +1417,11 @@ def POSIX : StandardSpec<"POSIX"> {
           RetValSpec<IntType>,
           [ArgSpec<IntType>, ArgSpec<IntType>, ArgSpec<IntType>]
         >,
+        FunctionSpec<
+          "bind",
+          RetValSpec<IntType>,
+          [ArgSpec<IntType>, ArgSpec<ConstStructSockAddrPtr>, ArgSpec<SocklenType>]
+        >,
       ]  // Functions
   >;
 
diff --git a/libc/src/sys/socket/CMakeLists.txt b/libc/src/sys/socket/CMakeLists.txt
index 7079d6e4466c683..d9e9922582074e8 100644
--- a/libc/src/sys/socket/CMakeLists.txt
+++ b/libc/src/sys/socket/CMakeLists.txt
@@ -9,3 +9,10 @@ add_entrypoint_object(
     .${LIBC_TARGET_OS}.socket
 )
 
+add_entrypoint_object(
+  bind
+  ALIAS
+  DEPENDS
+    .${LIBC_TARGET_OS}.bind
+)
+
diff --git a/libc/src/sys/socket/bind.h b/libc/src/sys/socket/bind.h
new file mode 100644
index 000000000000000..62e6221bf1b2d74
--- /dev/null
+++ b/libc/src/sys/socket/bind.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for bind --------------------------*- 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_BIND_H
+#define LLVM_LIBC_SRC_SYS_SOCKET_BIND_H
+
+#include <sys/socket.h>
+
+namespace LIBC_NAMESPACE {
+
+int bind(int domain, const struct sockaddr *address, socklen_t address_len);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_SYS_SOCKET_BIND_H
diff --git a/libc/src/sys/socket/linux/CMakeLists.txt b/libc/src/sys/socket/linux/CMakeLists.txt
index 41bcc9c9055f476..fc9febdec2cc3c3 100644
--- a/libc/src/sys/socket/linux/CMakeLists.txt
+++ b/libc/src/sys/socket/linux/CMakeLists.txt
@@ -10,3 +10,16 @@ add_entrypoint_object(
     libc.src.__support.OSUtil.osutil
     libc.src.errno.errno
 )
+
+add_entrypoint_object(
+  bind
+  SRCS
+    bind.cpp
+  HDRS
+    ../bind.h
+  DEPENDS
+    libc.include.sys_syscall
+    libc.include.sys_socket
+    libc.src.__support.OSUtil.osutil
+    libc.src.errno.errno
+)
diff --git a/libc/src/sys/socket/linux/bind.cpp b/libc/src/sys/socket/linux/bind.cpp
new file mode 100644
index 000000000000000..36afc646d29f6d0
--- /dev/null
+++ b/libc/src/sys/socket/linux/bind.cpp
@@ -0,0 +1,43 @@
+//===-- Linux implementation of bind --------------------------------------===//
+//
+// 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/bind.h"
+
+#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/common.h"
+
+#include "src/errno/libc_errno.h"
+
+#include <linux/net.h>   // For SYS_SOCKET socketcall number.
+#include <sys/syscall.h> // For syscall numbers.
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(int, bind,
+                   (int domain, const struct sockaddr *address,
+                    socklen_t address_len)) {
+#ifdef SYS_socket
+  int ret =
+      LIBC_NAMESPACE::syscall_impl<int>(SYS_bind, domain, address, address_len);
+#elif defined(SYS_socketcall)
+  unsigned long sockcall_args[3] = {static_cast<unsigned long>(domain),
+                                    reinterpret_cast<unsigned long>(address),
+                                    static_cast<unsigned long>(address_len)};
+  int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_socketcall, SYS_BIND,
+                                              sockcall_args);
+#else
+#error "socket and socketcall syscalls unavailable for this platform."
+#endif
+  if (ret < 0) {
+    libc_errno = -ret;
+    return -1;
+  }
+  return ret;
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/sys/socket/linux/socket.cpp b/libc/src/sys/socket/linux/socket.cpp
index 6429fd12013ea04..90a7dc632e26960 100644
--- a/libc/src/sys/socket/linux/socket.cpp
+++ b/libc/src/sys/socket/linux/socket.cpp
@@ -23,7 +23,9 @@ LLVM_LIBC_FUNCTION(int, socket, (int domain, int type, int protocol)) {
   int ret =
       LIBC_NAMESPACE::syscall_impl<int>(SYS_socket, domain, type, protocol);
 #elif defined(SYS_socketcall)
-  unsigned long sockcall_args[3] = {domain, type, protocol};
+  unsigned long sockcall_args[3] = {static_cast<unsigned long>(domain),
+                                    static_cast<unsigned long>(type),
+                                    static_cast<unsigned long>(protocol)};
   int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_socketcall, SYS_SOCKET,
                                               sockcall_args);
 #else
diff --git a/libc/test/src/sys/socket/linux/CMakeLists.txt b/libc/test/src/sys/socket/linux/CMakeLists.txt
index 4380597e5515799..666dc28c7e4ee19 100644
--- a/libc/test/src/sys/socket/linux/CMakeLists.txt
+++ b/libc/test/src/sys/socket/linux/CMakeLists.txt
@@ -12,3 +12,19 @@ add_libc_unittest(
     libc.src.sys.socket.socket
     libc.src.unistd.close
 )
+
+
+add_libc_unittest(
+  bind_test
+  SUITE
+    libc_sys_socket_unittests
+  SRCS
+    bind_test.cpp
+  DEPENDS
+    libc.include.sys_socket
+    libc.src.errno.errno
+    libc.src.sys.socket.socket
+    libc.src.sys.socket.bind
+    libc.src.stdio.remove
+    libc.src.unistd.close
+)
diff --git a/libc/test/src/sys/socket/linux/bind_test.cpp b/libc/test/src/sys/socket/linux/bind_test.cpp
new file mode 100644
index 000000000000000..5a3a1c227c9b58e
--- /dev/null
+++ b/libc/test/src/sys/socket/linux/bind_test.cpp
@@ -0,0 +1,55 @@
+//===-- Unittests for bind ------------------------------------------------===//
+//
+// 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/bind.h"
+#include "src/sys/socket/socket.h"
+
+#include "src/stdio/remove.h"
+#include "src/unistd/close.h"
+
+#include "src/errno/libc_errno.h"
+#include "test/UnitTest/LibcTest.h"
+#include "test/UnitTest/Test.h"
+
+#include <sys/socket.h> // For AF_UNIX and SOCK_DGRAM
+
+TEST(LlvmLibcSocketTest, BindLocalSocket) {
+
+  const char *FILENAME = "bind_file.test";
+  auto SOCK_PATH = libc_make_test_file_path(FILENAME);
+
+  int sock = LIBC_NAMESPACE::socket(AF_UNIX, SOCK_DGRAM, 0);
+  ASSERT_GE(sock, 0);
+  ASSERT_EQ(libc_errno, 0);
+
+  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];
+  my_addr.sun_path[i] = '\0';
+
+  // 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)));
+
+  int result =
+      LIBC_NAMESPACE::bind(sock, reinterpret_cast<struct sockaddr *>(&my_addr),
+                           sizeof(struct sockaddr_un));
+
+  ASSERT_EQ(result, 0);
+  ASSERT_EQ(libc_errno, 0);
+
+  LIBC_NAMESPACE::close(sock);
+
+  LIBC_NAMESPACE::remove(SOCK_PATH);
+}
diff --git a/libc/test/src/sys/socket/linux/socket_test.cpp b/libc/test/src/sys/socket/linux/socket_test.cpp
index 9037888441a357f..9d5bfacde0a4099 100644
--- a/libc/test/src/sys/socket/linux/socket_test.cpp
+++ b/libc/test/src/sys/socket/linux/socket_test.cpp
@@ -13,10 +13,10 @@
 #include "src/errno/libc_errno.h"
 #include "test/UnitTest/Test.h"
 
-#include <sys/socket.h> // For AF_LOCAL and SOCK_DGRAM
+#include <sys/socket.h> // For AF_UNIX and SOCK_DGRAM
 
 TEST(LlvmLibcSocketTest, LocalSocket) {
-  int sock = LIBC_NAMESPACE::socket(AF_LOCAL, SOCK_DGRAM, 0);
+  int sock = LIBC_NAMESPACE::socket(AF_UNIX, SOCK_DGRAM, 0);
   ASSERT_GE(sock, 0);
   ASSERT_EQ(libc_errno, 0);
 



More information about the libc-commits mailing list