diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td --- a/libc/config/linux/api.td +++ b/libc/config/linux/api.td @@ -203,6 +203,10 @@ "struct timeval"]; } +def SysSocketAPI : PublicAPI<"sys/socket.h"> { + let Types = ["struct sockaddr", "sa_family_t"]; +} + def SysResourceAPI : PublicAPI<"sys/resource.h"> { let Types = ["rlim_t", "struct rlimit"]; } diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -145,6 +145,9 @@ # sys/sendfile entrypoints libc.src.sys.sendfile.sendfile + # sys/socket.h entrypoints + libc.src.sys.socket.socket + # sys/stat.h entrypoints libc.src.sys.stat.chmod libc.src.sys.stat.fchmod diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt --- a/libc/include/CMakeLists.txt +++ b/libc/include/CMakeLists.txt @@ -388,6 +388,8 @@ DEPENDS .llvm_libc_common_h .llvm-libc-macros.sys_socket_macros + .llvm-libc-types.struct_sockaddr + .llvm-libc-types.sa_family_t ) add_gen_header( diff --git a/libc/include/llvm-libc-macros/linux/sys-socket-macros.h b/libc/include/llvm-libc-macros/linux/sys-socket-macros.h --- a/libc/include/llvm-libc-macros/linux/sys-socket-macros.h +++ b/libc/include/llvm-libc-macros/linux/sys-socket-macros.h @@ -18,4 +18,11 @@ #define AF_INET 2 // Internet IPv4 Protocol #define AF_INET6 10 // IP version 6 +#define SOCK_STREAM 1 +#define SOCK_DGRAM 2 +#define SOCK_RAW 3 +#define SOCK_RDM 4 +#define SOCK_SEQPACKET 5 +#define SOCK_PACKET 10 + #endif // __LLVM_LIBC_MACROS_LINUX_SYS_SOCKET_MACROS_H diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt --- a/libc/include/llvm-libc-types/CMakeLists.txt +++ b/libc/include/llvm-libc-types/CMakeLists.txt @@ -87,3 +87,5 @@ 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(struct_sockaddr HDR struct_sockaddr.h) diff --git a/libc/include/llvm-libc-types/sa_family_t.h b/libc/include/llvm-libc-types/sa_family_t.h new file mode 100644 --- /dev/null +++ b/libc/include/llvm-libc-types/sa_family_t.h @@ -0,0 +1,19 @@ +//===-- Definition of sa_family_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_SA_FAMILY_T_H__ +#define __LLVM_LIBC_TYPES_SA_FAMILY_T_H__ + +// The posix standard only says of sa_family_t that it must be unsigned. The +// linux man page for "address_families" lists approximately 32 different +// address families, meaning that a short 16 bit number will have plenty of +// space for all of them. + +typedef unsigned short sa_family_t; + +#endif // __LLVM_LIBC_TYPES_SA_FAMILY_T_H__ diff --git a/libc/include/llvm-libc-types/struct_sockaddr.h b/libc/include/llvm-libc-types/struct_sockaddr.h new file mode 100644 --- /dev/null +++ b/libc/include/llvm-libc-types/struct_sockaddr.h @@ -0,0 +1,21 @@ +//===-- Definition of struct stat -----------------------------------------===// +// +// 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_STAT_H__ +#define __LLVM_LIBC_TYPES_STRUCT_STAT_H__ + +#include + +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]; +}; + +#endif // __LLVM_LIBC_TYPES_STRUCT_STAT_H__ diff --git a/libc/spec/linux.td b/libc/spec/linux.td --- a/libc/spec/linux.td +++ b/libc/spec/linux.td @@ -110,19 +110,6 @@ ] >; - HeaderSpec SysSocket = HeaderSpec< - "sys/socket.h", - [ - Macro<"AF_UNSPEC">, - Macro<"AF_LOCAL">, - Macro<"AF_INET">, - Macro<"AF_INET6">, - ], - [], // Types - [], // Enumerations - [] // Functions - >; - HeaderSpec SysTime = HeaderSpec< "sys/time.h", [ @@ -184,7 +171,6 @@ SysMMan, SysPrctl, SysRandom, - SysSocket, SysTime, Signal, ]; diff --git a/libc/spec/posix.td b/libc/spec/posix.td --- a/libc/spec/posix.td +++ b/libc/spec/posix.td @@ -80,6 +80,10 @@ def GetoptArgvT : NamedType<"__getoptargv_t">; +def StructSockAddr : NamedType<"struct sockaddr">; +def StructSockAddrPtr : PtrType; +def SAFamilyType : NamedType<"sa_family_t">; + def POSIX : StandardSpec<"POSIX"> { PtrType CharPtr = PtrType; RestrictedPtrType RestrictedCharPtr = RestrictedPtrType; @@ -1347,6 +1351,34 @@ ] >; + HeaderSpec SysSocket = HeaderSpec< + "sys/socket.h", + [ + Macro<"AF_UNSPEC">, + Macro<"AF_UNIX">, + Macro<"AF_LOCAL">, + Macro<"AF_INET">, + Macro<"AF_INET6">, + Macro<"SOCK_STREAM">, + Macro<"SOCK_DGRAM">, + Macro<"SOCK_RAW">, + Macro<"SOCK_RDM">, + Macro<"SOCK_SEQPACKET">, + Macro<"SOCK_PACKET">, + ], // Macros + [ + StructSockAddr, SAFamilyType, + ], // Types + [], // Enumerations + [ + FunctionSpec< + "socket", + RetValSpec, + [ArgSpec, ArgSpec, ArgSpec] + >, + ] // Functions + >; + HeaderSpec SysTypes = HeaderSpec< "sys/types.h", [], // Macros @@ -1373,6 +1405,7 @@ SysMMan, SysResource, SysSelect, + SysSocket, SysStat, SysTypes, SysUtsName, diff --git a/libc/src/sys/CMakeLists.txt b/libc/src/sys/CMakeLists.txt --- a/libc/src/sys/CMakeLists.txt +++ b/libc/src/sys/CMakeLists.txt @@ -2,6 +2,7 @@ add_subdirectory(random) add_subdirectory(resource) add_subdirectory(select) +add_subdirectory(socket) add_subdirectory(sendfile) add_subdirectory(stat) add_subdirectory(utsname) diff --git a/libc/src/sys/socket/CMakeLists.txt b/libc/src/sys/socket/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/libc/src/sys/socket/CMakeLists.txt @@ -0,0 +1,11 @@ +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS}) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS}) +endif() + +add_entrypoint_object( + socket + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.socket +) + diff --git a/libc/src/sys/socket/linux/CMakeLists.txt b/libc/src/sys/socket/linux/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/libc/src/sys/socket/linux/CMakeLists.txt @@ -0,0 +1,12 @@ +add_entrypoint_object( + socket + SRCS + socket.cpp + HDRS + ../socket.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/socket.cpp b/libc/src/sys/socket/linux/socket.cpp new file mode 100644 --- /dev/null +++ b/libc/src/sys/socket/linux/socket.cpp @@ -0,0 +1,38 @@ +//===-- Linux implementation of socket ------------------------------------===// +// +// 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/socket.h" + +#include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/common.h" + +#include "src/errno/libc_errno.h" + +#include // For SYS_SOCKET socketcall number. +#include // For syscall numbers. + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(int, socket, (int domain, int type, int protocol)) { +#ifdef SYS_socket + long ret = __llvm_libc::syscall_impl(SYS_socket, domain, type, protocol); +#elif defined(SYS_socketcall) + unsigned long sockcall_args[3] = {domain, type, protocol}; + long ret = + __llvm_libc::syscall_impl(SYS_socketcall, SYS_SOCKET, sockcall_args); +#else +#error "socket and socketcall syscalls unavailable for this platform." +#endif + if (ret < 0) { + libc_errno = -ret; + return -1; + } + return ret; +} + +} // namespace __llvm_libc diff --git a/libc/src/sys/socket/socket.h b/libc/src/sys/socket/socket.h new file mode 100644 --- /dev/null +++ b/libc/src/sys/socket/socket.h @@ -0,0 +1,18 @@ +//===-- Implementation header for socket ------------------------*- 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_SENDFILE_H +#define LLVM_LIBC_SRC_SYS_SOCKET_SENDFILE_H + +namespace __llvm_libc { + +int socket(int domain, int type, int protocol); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_SYS_SOCKET_SENDFILE_H diff --git a/libc/test/src/sys/CMakeLists.txt b/libc/test/src/sys/CMakeLists.txt --- a/libc/test/src/sys/CMakeLists.txt +++ b/libc/test/src/sys/CMakeLists.txt @@ -3,6 +3,7 @@ add_subdirectory(resource) add_subdirectory(select) add_subdirectory(sendfile) +add_subdirectory(socket) add_subdirectory(stat) add_subdirectory(utsname) add_subdirectory(wait) diff --git a/libc/test/src/sys/socket/CMakeLists.txt b/libc/test/src/sys/socket/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/libc/test/src/sys/socket/CMakeLists.txt @@ -0,0 +1,3 @@ +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS}) + add_subdirectory(${LIBC_TARGET_OS}) +endif() diff --git a/libc/test/src/sys/socket/linux/CMakeLists.txt b/libc/test/src/sys/socket/linux/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/libc/test/src/sys/socket/linux/CMakeLists.txt @@ -0,0 +1,14 @@ +add_custom_target(libc_sys_socket_unittests) + +add_libc_unittest( + socket_test + SUITE + libc_sys_socket_unittests + SRCS + socket_test.cpp + DEPENDS + libc.include.sys_socket + libc.src.errno.errno + libc.src.sys.socket.socket + libc.src.unistd.close +) diff --git a/libc/test/src/sys/socket/linux/socket_test.cpp b/libc/test/src/sys/socket/linux/socket_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/sys/socket/linux/socket_test.cpp @@ -0,0 +1,24 @@ +//===-- Unittests for socket ----------------------------------------------===// +// +// 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/socket.h" + +#include "src/unistd/close.h" + +#include "src/errno/libc_errno.h" +#include "test/UnitTest/Test.h" + +#include // For AF_LOCAL and SOCK_DGRAM + +TEST(LlvmLibcSocketTest, LocalSocket) { + int sock = __llvm_libc::socket(AF_LOCAL, SOCK_DGRAM, 0); + ASSERT_GE(sock, 0); + ASSERT_EQ(libc_errno, 0); + + __llvm_libc::close(sock); +}