Imported Upstream version 5.4.0.167

Former-commit-id: 5624ac747d633e885131e8349322922b6a59baaa
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2017-08-21 15:34:15 +00:00
parent e49d6f06c0
commit 536cd135cc
12856 changed files with 563812 additions and 223249 deletions

View File

@@ -90,7 +90,9 @@ if (UPPERCASE_CMAKE_BUILD_TYPE STREQUAL DEBUG)
set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} ${CLR_SANITIZE_LINK_FLAGS} -Wl,--gc-sections")
endif ()
elseif (UPPERCASE_CMAKE_BUILD_TYPE STREQUAL RELEASE)
if (CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l AND DEFINED ENV{CROSSCOMPILE})
# Use O1 option when the clang version is smaller than 3.9
# Otherwise use O3 option in release build
if (CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l AND DEFINED ENV{CROSSCOMPILE} AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.9)
add_compile_options (-O1)
else()
add_compile_options (-O3)

View File

@@ -30,13 +30,14 @@
#cmakedefine01 HAVE_PRIVATE_FDS_BITS
#cmakedefine01 HAVE_STATFS
#cmakedefine01 HAVE_EPOLL
#cmakedefine01 HAVE_ACCEPT_4
#cmakedefine01 HAVE_ACCEPT4
#cmakedefine01 HAVE_KQUEUE
#cmakedefine01 HAVE_SENDFILE_4
#cmakedefine01 HAVE_SENDFILE_6
#cmakedefine01 HAVE_FCOPYFILE
#cmakedefine01 HAVE_GETHOSTBYNAME_R
#cmakedefine01 HAVE_GETHOSTBYADDR_R
#cmakedefine01 HAVE_GETNAMEINFO_SIGNED_FLAGS
#cmakedefine01 HAVE_GETPEEREID
#cmakedefine01 HAVE_SUPPORT_FOR_DUAL_MODE_IPV4_PACKET_INFO
#cmakedefine01 HAVE_THREAD_SAFE_GETHOSTBYNAME_AND_GETHOSTBYADDR
@@ -54,6 +55,7 @@
#cmakedefine01 HAVE_GETDOMAINNAME_SIZET
#cmakedefine01 HAVE_INOTIFY
#cmakedefine01 HAVE_CLOCK_MONOTONIC
#cmakedefine01 HAVE_CLOCK_REALTIME
#cmakedefine01 HAVE_MACH_ABSOLUTE_TIME
#cmakedefine01 HAVE_MACH_TIMEBASE_INFO
#cmakedefine01 HAVE_CURLM_ADDED_ALREADY
@@ -77,6 +79,7 @@
#cmakedefine01 IPV6MR_INTERFACE_UNSIGNED
#cmakedefine01 BIND_ADDRLEN_UNSIGNED
#cmakedefine01 INOTIFY_RM_WATCH_WD_UNSIGNED
#cmakedefine01 HAVE_IN_EXCL_UNLINK
// Mac OS X has stat64, but it is deprecated since plain stat now
// provides the same 64-bit aware struct when targeting OS X > 10.5

View File

@@ -16,6 +16,28 @@
#include <type_traits>
#include <unistd.h>
#ifdef DEBUG
#define assert_err(cond, msg, err) do \
{ \
if(!(cond)) \
{ \
fprintf(stderr, "%s (%d): error %d: %s. %s (%s failed)\n", __FILE__, __LINE__, err, msg, strerror(err), #cond); \
assert(false && "assert_err failed"); \
} \
} while(0)
#define assert_msg(cond, msg, val) do \
{ \
if(!(cond)) \
{ \
fprintf(stderr, "%s (%d): error %d: %s (%s failed)\n", __FILE__, __LINE__, val, msg, #cond); \
assert(false && "assert_msg failed"); \
} \
} while(0)
#else // DEBUG
#define assert_err(cond, msg, err)
#define assert_msg(cond, msg, val)
#endif // DEBUG
/**
* ResultOf<T> is shorthand for typename std::result_of<T>::type.
* Equivalent to C++14 std::result_of_t.

View File

@@ -18,6 +18,7 @@ set(NATIVE_SOURCES
pal_tcpstate.cpp
pal_time.cpp
pal_uid.cpp
pal_datetime.cpp
)
if (CMAKE_SYSTEM_NAME STREQUAL Linux)

View File

@@ -74,7 +74,7 @@ extern "C" void SystemNative_SetKeypadXmit(const char* terminfoString)
}
static bool g_readInProgress = false; // tracks whether a read is currently in progress, such that attributes have been changed
static bool g_signalForBreak = true; // tracks whether the terminal should send signals for breaks
static bool g_signalForBreak = true; // tracks whether the terminal should send signals for breaks, such that attributes have been changed
static bool g_haveInitTermios = false; // whether g_initTermios has been initialized
static struct termios g_initTermios = {}; // the initial attributes captured when Console was initialized
static struct termios g_preReadTermios = {}; // the original attributes captured before a read; valid if g_readInProgress is true
@@ -82,9 +82,18 @@ static struct termios g_currTermios = {}; // the current attributes set durin
static void UninitializeConsole()
{
// Put the attributes back to what they were when the console was initially initialized
if (g_haveInitTermios)
tcsetattr(STDIN_FILENO, TCSANOW, &g_initTermios); // ignore any failure
// Put the attributes back to what they were when the console was initially initialized.
// We only do so, however, if we have explicitly modified the termios; doing so always
// can result in problems if the app is in the background, as then attempting to call
// tcsetattr on STDIN_FILENO will suspend the app and prevent its shutdown. We also don't
// want to, for example, just compare g_currTermios with g_initTermios, as we'd then be
// factoring in changes made by other apps or by user code.
if (g_haveInitTermios && // we successfully initialized the console
(g_readInProgress || !g_signalForBreak)) // we modified attributes
{
tcsetattr(STDIN_FILENO, TCSANOW, &g_initTermios);
// ignore any failure
}
}
static void IncorporateBreak(struct termios *termios, int32_t signalForBreak)
@@ -374,7 +383,7 @@ void* SignalHandlerLoop(void* arg)
return nullptr;
}
assert(signalCode == SIGQUIT || signalCode == SIGINT);
assert_msg(signalCode == SIGQUIT || signalCode == SIGINT, "invalid signalCode", static_cast<int>(signalCode));
// We're now handling SIGQUIT and SIGINT. Invoke the callback, if we have one.
CtrlCallback callback = g_ctrlCallback;

View File

@@ -0,0 +1,40 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#include "pal_config.h"
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
#include <sys/time.h>
static const int64_t TICKS_PER_SECOND = 10000000; /* 10^7 */
#if HAVE_CLOCK_REALTIME
static const int64_t NANOSECONDS_PER_TICK = 100;
#else
static const int64_t TICKS_PER_MICROSECOND = 10; /* 1000 / 100 */
#endif
//
// SystemNative_GetSystemTimeAsTicks return the system time as ticks (100 nanoseconds)
// since 00:00 01 January 1970 UTC (Unix epoch)
//
extern "C" int64_t SystemNative_GetSystemTimeAsTicks()
{
#if HAVE_CLOCK_REALTIME
struct timespec time;
if (clock_gettime(CLOCK_REALTIME, &time) == 0)
{
return static_cast<int64_t>(time.tv_sec) * TICKS_PER_SECOND + (time.tv_nsec / NANOSECONDS_PER_TICK);
}
#else
struct timeval time;
if (gettimeofday(&time, NULL) == 0)
{
return static_cast<int64_t>(time.tv_sec) * TICKS_PER_SECOND + (time.tv_usec * TICKS_PER_MICROSECOND);
}
#endif
// in failure we return 00:00 01 January 1970 UTC (Unix epoch)
return 0;
}

View File

@@ -385,7 +385,7 @@ extern "C" int32_t SystemNative_ConvertErrorPalToPlatform(Error error)
// note that there is probably a corresponding missing case in the
// other direction above, but the compiler can't warn in that case
// because the platform values are not part of an enum.
assert(false && "Unknown error code");
assert_err(false, "Unknown error code", static_cast<int>(error));
return -1;
}
@@ -424,7 +424,7 @@ extern "C" const char* SystemNative_StrErrorR(int32_t platformErrno, char* buffe
// The only other valid error codes are 0 for success or EINVAL for
// an unknown error, but in the latter case a reasonable string (e.g
// "Unknown error: 0x123") is returned.
assert(error == 0 || error == EINVAL);
assert_err(error == 0 || error == EINVAL, "invalid error", error);
return buffer;
#endif
}

View File

@@ -45,6 +45,10 @@ extern "C" int32_t SystemNative_EnumerateInterfaceAddresses(IPv4AddressFound onI
for (ifaddrs* current = headAddr; current != nullptr; current = current->ifa_next)
{
if (current->ifa_addr == nullptr)
{
continue;
}
uint32_t interfaceIndex = if_nametoindex(current->ifa_name);
// ifa_name may be an aliased interface name.
// Use if_indextoname to map back to the true device name.

View File

@@ -134,12 +134,16 @@ static_assert(PAL_IN_Q_OVERFLOW == IN_Q_OVERFLOW, "");
static_assert(PAL_IN_IGNORED == IN_IGNORED, "");
static_assert(PAL_IN_ONLYDIR == IN_ONLYDIR, "");
static_assert(PAL_IN_DONT_FOLLOW == IN_DONT_FOLLOW, "");
#if HAVE_IN_EXCL_UNLINK
static_assert(PAL_IN_EXCL_UNLINK == IN_EXCL_UNLINK, "");
#endif // HAVE_IN_EXCL_UNLINK
static_assert(PAL_IN_ISDIR == IN_ISDIR, "");
#endif
#endif // HAVE_INOTIFY
static void ConvertFileStatus(const struct stat_& src, FileStatus* dst)
{
dst->Dev = static_cast<int64_t>(src.st_dev);
dst->Ino = static_cast<int64_t>(src.st_ino);
dst->Flags = FILESTATUS_FLAGS_NONE;
dst->Mode = static_cast<int32_t>(src.st_mode);
dst->Uid = src.st_uid;
@@ -213,13 +217,13 @@ static int32_t ConvertOpenFlags(int32_t flags)
ret = O_WRONLY;
break;
default:
assert(false && "Unknown Open access mode.");
assert_msg(false, "Unknown Open access mode", static_cast<int>(flags));
return -1;
}
if (flags & ~(PAL_O_ACCESS_MODE_MASK | PAL_O_CLOEXEC | PAL_O_CREAT | PAL_O_EXCL | PAL_O_TRUNC | PAL_O_SYNC))
{
assert(false && "Unknown Open flag.");
assert_msg(false, "Unknown Open flag", static_cast<int>(flags));
return -1;
}
@@ -260,7 +264,7 @@ extern "C" int32_t SystemNative_Close(intptr_t fd)
extern "C" intptr_t SystemNative_Dup(intptr_t oldfd)
{
int result;
while (CheckInterrupted(result = dup(ToFileDescriptor(oldfd))));
while (CheckInterrupted(result = fcntl(ToFileDescriptor(oldfd), F_DUPFD_CLOEXEC, 0)));
return result;
}
@@ -384,7 +388,7 @@ extern "C" int32_t SystemNative_ReadDirR(DIR* dir, void* buffer, int32_t bufferS
// kernel set errno -> failure
if (errno != 0)
{
assert(errno == EBADF); // Invalid directory stream descriptor dir.
assert_err(errno == EBADF, "Invalid directory stream descriptor dir", errno);
return errno;
}
return -1;
@@ -417,7 +421,7 @@ extern "C" int32_t SystemNative_Pipe(int32_t pipeFds[2], int32_t flags)
flags = O_CLOEXEC;
break;
default:
assert(false && "Unknown flag.");
assert_msg(false, "Unknown pipe flag", static_cast<int>(flags));
errno = EINVAL;
return -1;
}
@@ -642,7 +646,7 @@ static int32_t ConvertMMapProtection(int32_t protection)
if (protection & ~(PAL_PROT_READ | PAL_PROT_WRITE | PAL_PROT_EXEC))
{
assert(false && "Unknown protection.");
assert_msg(false, "Unknown protection", static_cast<int>(protection));
return -1;
}
@@ -662,7 +666,7 @@ static int32_t ConvertMMapFlags(int32_t flags)
{
if (flags & ~(PAL_MAP_SHARED | PAL_MAP_PRIVATE | PAL_MAP_ANONYMOUS))
{
assert(false && "Unknown MMap flag.");
assert_msg(false, "Unknown MMap flag", static_cast<int>(flags));
return -1;
}
@@ -682,7 +686,7 @@ static int32_t ConvertMSyncFlags(int32_t flags)
{
if (flags & ~(PAL_MS_SYNC | PAL_MS_ASYNC | PAL_MS_INVALIDATE))
{
assert(false && "Unknown MSync flag.");
assert_msg(false, "Unknown MSync flag", static_cast<int>(flags));
return -1;
}
@@ -774,7 +778,7 @@ extern "C" int32_t SystemNative_MAdvise(void* address, uint64_t length, MemoryAd
#endif
}
assert(false && "Unknown MemoryAdvice");
assert_msg(false, "Unknown MemoryAdvice", static_cast<int>(advice));
errno = EINVAL;
return -1;
}
@@ -849,7 +853,7 @@ extern "C" int64_t SystemNative_SysConf(SysConfName name)
return sysconf(_SC_NPROCESSORS_ONLN);
}
assert(false && "Unknown SysConfName");
assert_msg(false, "Unknown SysConf name", static_cast<int>(name));
errno = EINVAL;
return -1;
}
@@ -1218,6 +1222,9 @@ extern "C" int32_t SystemNative_INotifyAddWatch(intptr_t fd, const char* pathNam
assert(pathName != nullptr);
#if HAVE_INOTIFY
#if !HAVE_IN_EXCL_UNLINK
mask &= ~static_cast<uint32_t>(PAL_IN_EXCL_UNLINK);
#endif
return inotify_add_watch(ToFileDescriptor(fd), pathName, mask);
#else
(void)fd, (void)pathName, (void)mask;

View File

@@ -24,6 +24,8 @@ struct FileStatus
int64_t MTime; // time of last modification
int64_t CTime; // time of last status change
int64_t BirthTime; // time the file was created
int64_t Dev; // ID of the device containing the file
int64_t Ino; // inode number of the file
};
/************

View File

@@ -231,125 +231,10 @@ static int32_t ConvertGetAddrInfoAndGetNameInfoErrorsToPal(int32_t error)
return PAL_EAI_NONAME;
}
assert(false && "Unknown AddrInfo error flag");
assert_err(false, "Unknown AddrInfo error flag", error);
return -1;
}
extern "C" int32_t
SystemNative_IPv6StringToAddress(const uint8_t* address, const uint8_t* port, uint8_t* buffer, int32_t bufferLength, uint32_t* scope)
{
assert(buffer != nullptr);
assert(bufferLength == NUM_BYTES_IN_IPV6_ADDRESS);
assert(scope != nullptr);
assert(address != nullptr);
addrinfo hint;
memset(&hint, 0, sizeof(addrinfo));
hint.ai_family = AF_INET6;
hint.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
addrinfo* info = nullptr;
int32_t result = getaddrinfo(reinterpret_cast<const char*>(address), reinterpret_cast<const char*>(port), &hint, &info);
if (result == 0)
{
sockaddr_in6* addr = reinterpret_cast<sockaddr_in6*>(info->ai_addr);
ConvertIn6AddrToByteArray(buffer, bufferLength, addr->sin6_addr);
*scope = addr->sin6_scope_id;
freeaddrinfo(info);
}
return ConvertGetAddrInfoAndGetNameInfoErrorsToPal(result);
}
extern "C" int32_t SystemNative_IPv4StringToAddress(const uint8_t* address, uint8_t* buffer, int32_t bufferLength, uint16_t* port)
{
assert(buffer != nullptr);
assert(bufferLength == NUM_BYTES_IN_IPV4_ADDRESS);
assert(port != nullptr);
assert(address != nullptr);
in_addr inaddr;
int32_t result = inet_aton(reinterpret_cast<const char*>(address), &inaddr);
if (result == 0)
{
return PAL_EAI_NONAME;
}
ConvertInAddrToByteArray(buffer, bufferLength, inaddr);
*port = 0; // callers expect this to always be zero
return PAL_EAI_SUCCESS;
}
static void AppendScopeIfNecessary(uint8_t* string, int32_t stringLength, uint32_t scope)
{
assert(scope != 0);
// Find the scope ID, if it exists
int i;
for (i = 0; i < stringLength && string[i] != '\0'; i++)
{
if (string[i] == '%')
{
// Found a scope ID. Assume it's correct and return.
return;
}
}
auto capacity = static_cast<size_t>(stringLength - i);
int n = snprintf(reinterpret_cast<char*>(&string[i]), capacity, "%%%d", scope);
assert(static_cast<size_t>(n) < capacity);
(void)n; // Silence an unused variable warning in release mode
}
extern "C" int32_t SystemNative_IPAddressToString(
const uint8_t* address, int32_t addressLength, bool isIPv6, uint8_t* string, int32_t stringLength, uint32_t scope)
{
assert(address != nullptr);
assert((addressLength == NUM_BYTES_IN_IPV6_ADDRESS) || (addressLength == NUM_BYTES_IN_IPV4_ADDRESS));
assert(string != nullptr);
// These constants differ per platform so the managed side uses the bigger value; therefore, check that
// the length is between the two lengths
assert((stringLength >= INET_ADDRSTRLEN) && (stringLength <= INET6_ADDRSTRLEN_MANAGED));
socklen_t len = UnsignedCast(stringLength);
sockaddr_in inAddr;
sockaddr_in6 in6Addr;
const sockaddr* addr;
socklen_t addrLen;
if (!isIPv6)
{
ConvertByteArrayToSockAddrIn(inAddr, address, addressLength);
addr = reinterpret_cast<const sockaddr*>(&inAddr);
addrLen = sizeof(inAddr);
}
else
{
in6Addr.sin6_scope_id = scope;
ConvertByteArrayToSockAddrIn6(in6Addr, address, addressLength);
addr = reinterpret_cast<const sockaddr*>(&in6Addr);
addrLen = sizeof(in6Addr);
}
int result = getnameinfo(addr, addrLen, reinterpret_cast<char*>(string), len, nullptr, 0, NI_NUMERICHOST);
if (result != 0)
{
return ConvertGetAddrInfoAndGetNameInfoErrorsToPal(result);
}
// Some platforms do not append unknown scope IDs, but the managed code wants this behavior.
if (isIPv6 && scope != 0)
{
AppendScopeIfNecessary(string, stringLength, scope);
}
return 0;
}
extern "C" int32_t SystemNative_GetHostEntryForName(const uint8_t* address, HostEntry* entry)
{
if (address == nullptr || entry == nullptr)
@@ -411,7 +296,7 @@ static int ConvertGetHostErrorPlatformToPal(int error)
return PAL_NO_DATA;
default:
assert(false && "Unknown gethostbyname/gethostbyaddr error code");
assert_err(false, "Unknown gethostbyname/gethostbyaddr error code", error);
return PAL_HOST_NOT_FOUND;
}
}
@@ -554,29 +439,29 @@ static int GetHostByNameHelper(const uint8_t* hostname, hostent** entry)
hostent* result = reinterpret_cast<hostent*>(buffer);
char* scratch = reinterpret_cast<char*>(&buffer[sizeof(hostent)]);
int getHostErrno;
int getHostErrno = 0;
int err = gethostbyname_r(reinterpret_cast<const char*>(hostname), result, scratch, scratchLen, entry, &getHostErrno);
switch (err)
if (!err && *entry != nullptr)
{
case 0:
*entry = result;
return 0;
case ERANGE:
free(buffer);
size_t tmpScratchLen;
if (!multiply_s(scratchLen, static_cast<size_t>(2), &tmpScratchLen))
{
*entry = nullptr;
return PAL_NO_MEM;
}
scratchLen = tmpScratchLen;
break;
default:
free(buffer);
assert(*entry == result);
return 0;
}
else if (err == ERANGE)
{
free(buffer);
size_t tmpScratchLen;
if (!multiply_s(scratchLen, static_cast<size_t>(2), &tmpScratchLen))
{
*entry = nullptr;
return getHostErrno;
return PAL_NO_MEM;
}
scratchLen = tmpScratchLen;
}
else
{
free(buffer);
*entry = nullptr;
return getHostErrno ? getHostErrno : HOST_NOT_FOUND;
}
}
}
@@ -633,29 +518,29 @@ static int GetHostByAddrHelper(const uint8_t* addr, const socklen_t addrLen, int
hostent* result = reinterpret_cast<hostent*>(buffer);
char* scratch = reinterpret_cast<char*>(&buffer[sizeof(hostent)]);
int getHostErrno;
int getHostErrno = 0;
int err = gethostbyaddr_r(addr, addrLen, type, result, scratch, scratchLen, entry, &getHostErrno);
switch (err)
if (!err && *entry != nullptr)
{
case 0:
*entry = result;
return 0;
case ERANGE:
free(buffer);
size_t tmpScratchLen;
if (!multiply_s(scratchLen, static_cast<size_t>(2), &tmpScratchLen))
{
*entry = nullptr;
return PAL_NO_MEM;
}
scratchLen = tmpScratchLen;
break;
default:
free(buffer);
assert(*entry == result);
return 0;
}
else if (err == ERANGE)
{
free(buffer);
size_t tmpScratchLen;
if (!multiply_s(scratchLen, static_cast<size_t>(2), &tmpScratchLen))
{
*entry = nullptr;
return getHostErrno;
return PAL_NO_MEM;
}
scratchLen = tmpScratchLen;
}
else
{
free(buffer);
*entry = nullptr;
return getHostErrno ? getHostErrno : HOST_NOT_FOUND;
}
}
}
@@ -838,9 +723,16 @@ extern "C" void SystemNative_FreeHostEntry(HostEntry* entry)
}
}
inline int32_t ConvertGetNameInfoFlagsToNative(int32_t flags)
// There were several versions of glibc that had the flags parameter of getnameinfo unsigned
#if HAVE_GETNAMEINFO_SIGNED_FLAGS
typedef int32_t NativeFlagsType;
#else
typedef uint32_t NativeFlagsType;
#endif
inline NativeFlagsType ConvertGetNameInfoFlagsToNative(int32_t flags)
{
int32_t outFlags = 0;
NativeFlagsType outFlags = 0;
if ((flags & PAL_NI_NAMEREQD) == PAL_NI_NAMEREQD)
{
outFlags |= NI_NAMEREQD;
@@ -867,7 +759,7 @@ extern "C" int32_t SystemNative_GetNameInfo(const uint8_t* address,
assert((host != nullptr) || (service != nullptr));
assert((hostLength > 0) || (serviceLength > 0));
int32_t nativeFlags = ConvertGetNameInfoFlagsToNative(flags);
NativeFlagsType nativeFlags = ConvertGetNameInfoFlagsToNative(flags);
int32_t result;
if (isIPv6)
@@ -1474,7 +1366,7 @@ extern "C" Error SystemNative_GetIPv6MulticastOption(intptr_t socket, int32_t mu
int fd = ToFileDescriptor(socket);
int optionName;
if (!GetMulticastOptionName(multicastOption, false, optionName))
if (!GetMulticastOptionName(multicastOption, true, optionName))
{
return PAL_EINVAL;
}
@@ -1502,7 +1394,7 @@ extern "C" Error SystemNative_SetIPv6MulticastOption(intptr_t socket, int32_t mu
int fd = ToFileDescriptor(socket);
int optionName;
if (!GetMulticastOptionName(multicastOption, false, optionName))
if (!GetMulticastOptionName(multicastOption, true, optionName))
{
return PAL_EINVAL;
}
@@ -1752,7 +1644,7 @@ extern "C" Error SystemNative_Accept(intptr_t socket, uint8_t* socketAddress, in
socklen_t addrLen = static_cast<socklen_t>(*socketAddressLen);
int accepted;
#if defined(HAVE_ACCEPT_4) && defined(SOCK_CLOEXEC)
#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
while (CheckInterrupted(accepted = accept4(fd, reinterpret_cast<sockaddr*>(socketAddress), &addrLen, SOCK_CLOEXEC)));
#else
while (CheckInterrupted(accepted = accept(fd, reinterpret_cast<sockaddr*>(socketAddress), &addrLen)));
@@ -2456,7 +2348,8 @@ static Error TryChangeSocketEventRegistrationInner(
op = EPOLL_CTL_DEL;
}
epoll_event evt = {.events = GetEPollEvents(newEvents) | EPOLLET, .data = {.ptr = reinterpret_cast<void*>(data)}};
epoll_event evt = {.events = GetEPollEvents(newEvents) | static_cast<unsigned int>(EPOLLET),
.data = {.ptr = reinterpret_cast<void*>(data)}};
int err = epoll_ctl(port, op, socket, &evt);
return err == 0 ? PAL_SUCCESS : SystemNative_ConvertErrorPlatformToPal(errno);
}
@@ -2558,7 +2451,7 @@ static SocketEvents GetSocketEvents(int16_t filter, uint16_t flags)
break;
default:
assert(false && "unexpected kqueue filter type");
assert_msg(false, "unexpected kqueue filter type", static_cast<int>(filter));
return PAL_SA_NONE;
}
@@ -2840,27 +2733,48 @@ extern "C" Error SystemNative_SendFile(intptr_t out_fd, intptr_t in_fd, int64_t
*sent = 0;
return SystemNative_ConvertErrorPlatformToPal(errno);
#elif HAVE_SENDFILE_6
off_t len = count;
ssize_t res;
while (CheckInterrupted(res = sendfile(infd, outfd, static_cast<off_t>(offset), &len, nullptr, 0)));
if (res != -1)
*sent = 0;
while (true) // in case we need to retry for an EINTR
{
if (len == 0)
off_t len = count;
ssize_t res = sendfile(infd, outfd, static_cast<off_t>(offset), &len, nullptr, 0);
assert(len >= 0);
// If the call succeeded, store the number of bytes sent, and return. We add
// rather than copy len because a previous call to sendfile could have sent bytes
// but been interrupted by EINTR, in which case we need to add to that.
if (res != -1)
{
// This indicates EOF
*sent = count;
*sent += len;
return PAL_SUCCESS;
}
else
// We got an error. If sendfile "fails" with EINTR or EAGAIN, it may have sent
// some data that needs to be counted.
if (errno == EAGAIN || errno == EINTR)
{
*sent = len;
*sent += len;
offset += len;
count -= len;
// If we actually transferred everything in spite of the error, return success.
assert(count >= 0);
if (count == 0) return PAL_SUCCESS;
// For EINTR, loop around and go again.
if (errno == EINTR) continue;
}
return PAL_SUCCESS;
// For everything other than EINTR, bail.
return SystemNative_ConvertErrorPlatformToPal(errno);
}
*sent = 0;
return SystemNative_ConvertErrorPlatformToPal(errno);
#else
#else
// If we ever need to run on a platform that doesn't have sendfile,
// we can implement this with a simple read/send loop. For now,
// we just mark it as not supported.
(void)outfd;
(void)infd;
(void)offset;

View File

@@ -293,21 +293,6 @@ struct SocketEvent
uint32_t Padding; // Pad out to 8-byte alignment
};
/**
* Converts string-representations of IP Addresses to
*/
extern "C" int32_t SystemNative_IPv6StringToAddress(
const uint8_t* address, const uint8_t* port, uint8_t* buffer, int32_t bufferLength, uint32_t* scope);
extern "C" int32_t SystemNative_IPv4StringToAddress(const uint8_t* address, uint8_t* buffer, int32_t bufferLength, uint16_t* port);
extern "C" int32_t SystemNative_IPAddressToString(const uint8_t* address,
int32_t addressLength,
bool isIPv6,
uint8_t* string,
int32_t stringLength,
uint32_t scope = 0);
extern "C" int32_t SystemNative_GetHostEntryForName(const uint8_t* address, HostEntry* entry);
extern "C" int32_t SystemNative_GetHostByName(const uint8_t* hostname, HostEntry* entry);

View File

@@ -4,6 +4,7 @@
#include "pal_config.h"
#include "pal_process.h"
#include "pal_io.h"
#include "pal_utilities.h"
#include <assert.h>
@@ -136,9 +137,11 @@ extern "C" int32_t SystemNative_ForkAndExecProcess(const char* filename,
goto done;
}
// Open pipes for any requests to redirect stdin/stdout/stderr
if ((redirectStdin && pipe(stdinFds) != 0) || (redirectStdout && pipe(stdoutFds) != 0) ||
(redirectStderr && pipe(stderrFds) != 0))
// Open pipes for any requests to redirect stdin/stdout/stderr and set the
// close-on-exec flag to the pipe file descriptors.
if ((redirectStdin && SystemNative_Pipe(stdinFds, PAL_O_CLOEXEC) != 0) ||
(redirectStdout && SystemNative_Pipe(stdoutFds, PAL_O_CLOEXEC) != 0) ||
(redirectStderr && SystemNative_Pipe(stderrFds, PAL_O_CLOEXEC) != 0))
{
success = false;
goto done;
@@ -163,22 +166,14 @@ extern "C" int32_t SystemNative_ForkAndExecProcess(const char* filename,
if (processId == 0) // processId == 0 if this is child process
{
// Close the child's copy of the parent end of any open pipes
CloseIfOpen(stdinFds[WRITE_END_OF_PIPE]);
CloseIfOpen(stdoutFds[READ_END_OF_PIPE]);
CloseIfOpen(stderrFds[READ_END_OF_PIPE]);
// For any redirections that should happen, dup the pipe descriptors onto stdin/out/err.
// Then close out the old pipe descriptrs, which we no longer need.
// We don't need to explicitly close out the old pipe descriptors as they will be closed on the 'execve' call.
if ((redirectStdin && Dup2WithInterruptedRetry(stdinFds[READ_END_OF_PIPE], STDIN_FILENO) == -1) ||
(redirectStdout && Dup2WithInterruptedRetry(stdoutFds[WRITE_END_OF_PIPE], STDOUT_FILENO) == -1) ||
(redirectStderr && Dup2WithInterruptedRetry(stderrFds[WRITE_END_OF_PIPE], STDERR_FILENO) == -1))
{
_exit(errno != 0 ? errno : EXIT_FAILURE);
}
CloseIfOpen(stdinFds[READ_END_OF_PIPE]);
CloseIfOpen(stdoutFds[WRITE_END_OF_PIPE]);
CloseIfOpen(stderrFds[WRITE_END_OF_PIPE]);
// Change to the designated working directory, if one was specified
if (nullptr != cwd)
@@ -285,7 +280,7 @@ static int32_t ConvertRLimitResourcesPalToPlatform(RLimitResources value)
return RLIMIT_NOFILE;
}
assert(false && "Unknown RLIMIT value");
assert_msg(false, "Unknown RLIMIT value", static_cast<int>(value));
return -1;
}
@@ -438,7 +433,7 @@ extern "C" int64_t SystemNative_PathConf(const char* path, PathConfName name)
if (confValue == -1)
{
assert(false && "Unknown PathConfName");
assert_msg(false, "Unknown PathConfName", static_cast<int>(name));
errno = EINVAL;
return -1;
}

View File

@@ -40,6 +40,11 @@ static_assert(PAL_CURL_VERSION_UNIX_SOCKETS == CURL_VERSION_UNIX_SOCKETS, "");
static_assert(PAL_CURL_VERSION_PSL == CURL_VERSION_PSL, "");
#endif
// Based on docs/libcurl/symbols-in-versions in libcurl source tree,
// the CURL_VERSION_HTTP2 was introduced in libcurl 7.33.0 and
// the CURLPIPE_MULTIPLEX was introduced in libcurl 7.43.0.
#define MIN_VERSION_WITH_CURLPIPE_MULTIPLEX 0x074300
extern "C" int32_t HttpNative_GetSupportedFeatures()
{
curl_version_info_data* info = curl_version_info(CURLVERSION_NOW);
@@ -48,12 +53,10 @@ extern "C" int32_t HttpNative_GetSupportedFeatures()
extern "C" int32_t HttpNative_GetSupportsHttp2Multiplexing()
{
#if HAVE_CURLPIPE_MULTIPLEX
curl_version_info_data* info = curl_version_info(CURLVERSION_NOW);
return info != nullptr && (info->features & CURL_VERSION_HTTP2) == CURL_VERSION_HTTP2 ? 1 : 0;
#else
return 0;
#endif
return info != nullptr &&
(info->version_num >= MIN_VERSION_WITH_CURLPIPE_MULTIPLEX) &&
((info->features & PAL_CURL_VERSION_HTTP2) == PAL_CURL_VERSION_HTTP2) ? 1 : 0;
}
extern "C" char* HttpNative_GetVersionDescription()
@@ -67,39 +70,3 @@ extern "C" char* HttpNative_GetSslVersionDescription()
curl_version_info_data* info = curl_version_info(CURLVERSION_NOW);
return info != nullptr && info->ssl_version != nullptr ? strdup(info->ssl_version) : nullptr;
}
// TODO: Remove HttpNative_GetCurlVersionInfo once the build containing the above functions
// is available as part of a package.
extern "C" int32_t HttpNative_GetCurlVersionInfo(int32_t* age,
int32_t* supportsSsl,
int32_t* supportsAutoDecompression,
int32_t* supportsHttp2Multiplexing)
{
curl_version_info_data* versionInfo = curl_version_info(CURLVERSION_NOW);
if (!versionInfo || !age || !supportsSsl || !supportsAutoDecompression || !supportsHttp2Multiplexing)
{
if (age)
*age = 0;
if (supportsSsl)
*supportsSsl = 0;
if (supportsAutoDecompression)
*supportsAutoDecompression = 0;
if (supportsHttp2Multiplexing)
*supportsHttp2Multiplexing = 0;
return 0;
}
*age = versionInfo->age;
*supportsSsl = (versionInfo->features & CURL_VERSION_SSL) == CURL_VERSION_SSL;
*supportsAutoDecompression = (versionInfo->features & CURL_VERSION_LIBZ) == CURL_VERSION_LIBZ;
*supportsHttp2Multiplexing =
#if HAVE_CURLPIPE_MULTIPLEX
(versionInfo->features & CURL_VERSION_HTTP2) == CURL_VERSION_HTTP2;
#else
0;
#endif
return 1;
}

View File

@@ -67,6 +67,15 @@ extern "C" int32_t AppleCryptoNative_SecKeychainOpen(const char* pszKeychainPath
return SecKeychainOpen(pszKeychainPath, pKeychainOut);
}
extern "C" int32_t AppleCryptoNative_SetKeychainNeverLock(SecKeychainRef keychain)
{
SecKeychainSettings settings = {
.version = SEC_KEYCHAIN_SETTINGS_VERS1, .useLockInterval = 0, .lockOnSleep = 0, .lockInterval = INT_MAX,
};
return SecKeychainSetSettings(keychain, &settings);
}
static int32_t
EnumerateKeychain(SecKeychainRef keychain, CFStringRef matchType, CFArrayRef* pCertsOut, int32_t* pOSStatus)
{

View File

@@ -60,6 +60,13 @@ pKeychainOut: Receives the SecKeychainRef for the named keychain.
*/
extern "C" int32_t AppleCryptoNative_SecKeychainOpen(const char* pszKeychainPath, SecKeychainRef* pKeychainOut);
/*
Set a keychain to never (automatically) lock.
Returns the result of SecKeychainSetSettings to a never-auto-lock policy.
*/
extern "C" int32_t AppleCryptoNative_SetKeychainNeverLock(SecKeychainRef keychain);
/*
Enumerate the certificate objects within the given keychain.

View File

@@ -488,3 +488,191 @@ extern "C" int32_t AppleCryptoNative_X509GetRawData(SecCertificateRef cert, CFDa
*pOSStatus = SecItemExport(cert, dataFormat, 0, &keyParams, ppDataOut);
return (*pOSStatus == noErr);
}
static OSStatus AddKeyToKeychain(SecKeyRef privateKey, SecKeychainRef targetKeychain)
{
// This is quite similar to pal_seckey's ExportImportKey, but
// a) is used to put something INTO a keychain, instead of to take it out.
// b) Doesn't assume that the input should be CFRelease()d and overwritten.
// c) Doesn't return/emit the imported key reference.
// d) Works on private keys.
SecExternalFormat dataFormat = kSecFormatWrappedPKCS8;
CFDataRef exportData = nullptr;
SecItemImportExportKeyParameters keyParams = {};
keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
keyParams.passphrase = CFSTR("ExportImportPassphrase");
OSStatus status = SecItemExport(privateKey, dataFormat, 0, &keyParams, &exportData);
SecExternalFormat actualFormat = dataFormat;
SecExternalItemType actualType = kSecItemTypePrivateKey;
CFArrayRef outItems = nullptr;
if (status == noErr)
{
status =
SecItemImport(exportData, nullptr, &actualFormat, &actualType, 0, &keyParams, targetKeychain, &outItems);
}
if (exportData != nullptr)
CFRelease(exportData);
CFRelease(keyParams.passphrase);
keyParams.passphrase = nullptr;
if (outItems != nullptr)
CFRelease(outItems);
return status;
}
extern "C" int32_t AppleCryptoNative_X509CopyWithPrivateKey(SecCertificateRef cert,
SecKeyRef privateKey,
SecKeychainRef targetKeychain,
SecIdentityRef* pIdentityOut,
int32_t* pOSStatus)
{
if (pIdentityOut != nullptr)
*pIdentityOut = nullptr;
if (pOSStatus != nullptr)
*pOSStatus = noErr;
if (cert == nullptr || privateKey == nullptr || targetKeychain == nullptr || pIdentityOut == nullptr ||
pOSStatus == nullptr)
{
return -1;
}
SecKeychainRef keyKeychain = nullptr;
OSStatus status = SecKeychainItemCopyKeychain(reinterpret_cast<SecKeychainItemRef>(privateKey), &keyKeychain);
SecKeychainItemRef itemCopy = nullptr;
// This only happens with an ephemeral key, so the keychain we're adding it to is temporary.
if (status == errSecNoSuchKeychain)
{
status = AddKeyToKeychain(privateKey, targetKeychain);
}
if (itemCopy != nullptr)
{
CFRelease(itemCopy);
}
CFMutableDictionaryRef query = nullptr;
if (status == noErr)
{
query = CFDictionaryCreateMutable(
kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (query == nullptr)
{
status = errSecAllocate;
}
}
CFArrayRef searchList = nullptr;
if (status == noErr)
{
searchList = CFArrayCreate(
nullptr, const_cast<const void**>(reinterpret_cast<void**>(&targetKeychain)), 1, &kCFTypeArrayCallBacks);
if (searchList == nullptr)
{
status = errSecAllocate;
}
}
CFArrayRef itemMatch = nullptr;
if (status == noErr)
{
itemMatch = CFArrayCreate(
nullptr, const_cast<const void**>(reinterpret_cast<void**>(&cert)), 1, &kCFTypeArrayCallBacks);
if (itemMatch == nullptr)
{
status = errSecAllocate;
}
}
CFTypeRef result = nullptr;
if (status == noErr)
{
CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue);
CFDictionarySetValue(query, kSecMatchSearchList, searchList);
CFDictionarySetValue(query, kSecMatchItemList, itemMatch);
CFDictionarySetValue(query, kSecClass, kSecClassIdentity);
status = SecItemCopyMatching(query, &result);
if (status != noErr && result != nullptr)
{
CFRelease(result);
result = nullptr;
}
bool added = false;
if (status == errSecItemNotFound)
{
status = SecCertificateAddToKeychain(cert, targetKeychain);
added = (status == noErr);
}
if (result == nullptr && status == noErr)
{
status = SecItemCopyMatching(query, &result);
}
if (result != nullptr && status == noErr)
{
if (CFGetTypeID(result) != SecIdentityGetTypeID())
{
status = errSecItemNotFound;
}
else
{
SecIdentityRef identity = reinterpret_cast<SecIdentityRef>(const_cast<void*>(result));
CFRetain(identity);
*pIdentityOut = identity;
}
}
if (added)
{
// The same query that was used to find the identity can be used
// to find/delete the certificate, as long as we fix the class to just the cert.
CFDictionarySetValue(query, kSecClass, kSecClassCertificate);
// Ignore the output status, there's no point in telling the user
// that the cleanup failed, since that just makes them have a dirty keychain
// AND their program didn't work.
SecItemDelete(query);
}
}
if (result != nullptr)
CFRelease(result);
if (itemMatch != nullptr)
CFRelease(itemMatch);
if (searchList != nullptr)
CFRelease(searchList);
if (query != nullptr)
CFRelease(query);
if (keyKeychain != nullptr)
CFRelease(keyKeychain);
*pOSStatus = status;
return status == noErr;
}

View File

@@ -156,3 +156,20 @@ ppDataOut: Receives a CFDataRef with the exported blob
pOSStatus: Receives the result of SecItemExport
*/
extern "C" int32_t AppleCryptoNative_X509GetRawData(SecCertificateRef cert, CFDataRef* ppDataOut, int32_t* pOSStatus);
/*
Find a SecIdentityRef for the given cert and private key in the target keychain.
If the key does not belong to any keychain it is added to the target keychain and left there.
If the certificate does not belong to the target keychain it is added and removed.
Returns 1 on success, 0 on failure, any other value indicates invalid state.
Output:
pIdentityOut: Receives the SecIdentityRef of the mated cert/key pair.
pOSStatus: Receives the result of the last executed system call.
*/
extern "C" int32_t AppleCryptoNative_X509CopyWithPrivateKey(SecCertificateRef cert,
SecKeyRef privateKey,
SecKeychainRef targetKeychain,
SecIdentityRef* pIdentityOut,
int32_t* pOSStatus);

View File

@@ -19,7 +19,7 @@ extern "C" SecPolicyRef AppleCryptoNative_X509ChainCreateDefaultPolicy()
extern "C" SecPolicyRef AppleCryptoNative_X509ChainCreateRevocationPolicy()
{
return SecPolicyCreateRevocation(kSecRevocationUseAnyAvailableMethod);
return SecPolicyCreateRevocation(kSecRevocationUseAnyAvailableMethod | kSecRevocationRequirePositiveResponse);
}
extern "C" int32_t
@@ -163,6 +163,8 @@ static void MergeStatusCodes(CFTypeRef key, CFTypeRef value, void* context)
*pStatus |= PAL_X509ChainInvalidBasicConstraints;
else if (CFEqual(keyString, CFSTR("UsageConstraints")))
*pStatus |= PAL_X509ChainExplicitDistrust;
else if (CFEqual(keyString, CFSTR("RevocationResponseRequired")))
*pStatus |= PAL_X509ChainRevocationStatusUnknown;
else if (CFEqual(keyString, CFSTR("WeakLeaf")) || CFEqual(keyString, CFSTR("WeakIntermediates")) ||
CFEqual(keyString, CFSTR("WeakRoot")))
{
@@ -175,6 +177,9 @@ static void MergeStatusCodes(CFTypeRef key, CFTypeRef value, void* context)
else
{
#ifdef DEBUGGING_UNKNOWN_VALUE
printf("%s\n", CFStringGetCStringPtr(keyString, CFStringGetSystemEncoding()));
#endif
*pStatus |= PAL_X509ChainErrorUnknownValue;
}
}
@@ -233,6 +238,8 @@ extern "C" int32_t AppleCryptoNative_GetOSStatusForChainStatus(PAL_X509ChainStat
return errSecCreateChainFailed;
case PAL_X509ChainExplicitDistrust:
return errSecTrustSettingDeny;
case PAL_X509ChainRevocationStatusUnknown:
return errSecIncompleteCertRevocationCheck;
default:
return errSecCoreFoundationUnknown;
}

View File

@@ -56,18 +56,12 @@ endif()
add_library(objlib OBJECT ${NATIVECRYPTO_SOURCES} ${VERSION_FILE_PATH})
add_library(System.Security.Cryptography.Native
SHARED
$<TARGET_OBJECTS:objlib>
)
add_library(System.Security.Cryptography.Native.OpenSsl
SHARED
$<TARGET_OBJECTS:objlib>
)
# Disable the "lib" prefix.
set_target_properties(System.Security.Cryptography.Native PROPERTIES PREFIX "")
set_target_properties(System.Security.Cryptography.Native.OpenSsl PROPERTIES PREFIX "")
if (FEATURE_DISTRO_AGNOSTIC_SSL)
@@ -80,19 +74,10 @@ if (FEATURE_DISTRO_AGNOSTIC_SSL)
)
# Link with libdl.so to get the dlopen / dlsym / dlclose
target_link_libraries(System.Security.Cryptography.Native
dl
)
target_link_libraries(System.Security.Cryptography.Native.OpenSsl
dl
)
else()
target_link_libraries(System.Security.Cryptography.Native
${OPENSSL_CRYPTO_LIBRARY}
${OPENSSL_SSL_LIBRARY}
)
target_link_libraries(System.Security.Cryptography.Native.OpenSsl
${OPENSSL_CRYPTO_LIBRARY}
${OPENSSL_SSL_LIBRARY}
@@ -107,12 +92,6 @@ else()
#
# So, after compiling, rewrite the references to libcrypto to be more flexible.
if (APPLE)
add_custom_command(TARGET System.Security.Cryptography.Native POST_BUILD
COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib @rpath/libcrypto.1.0.0.dylib $<TARGET_FILE:System.Security.Cryptography.Native>
COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change /usr/local/opt/openssl/lib/libssl.1.0.0.dylib @rpath/libssl.1.0.0.dylib $<TARGET_FILE:System.Security.Cryptography.Native>
COMMAND ${CMAKE_INSTALL_NAME_TOOL} -add_rpath @loader_path $<TARGET_FILE:System.Security.Cryptography.Native>
)
add_custom_command(TARGET System.Security.Cryptography.Native.OpenSsl POST_BUILD
COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib @rpath/libcrypto.1.0.0.dylib $<TARGET_FILE:System.Security.Cryptography.Native.OpenSsl>
COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change /usr/local/opt/openssl/lib/libssl.1.0.0.dylib @rpath/libssl.1.0.0.dylib $<TARGET_FILE:System.Security.Cryptography.Native.OpenSsl>
@@ -123,5 +102,4 @@ endif()
include(configure.cmake)
install_library_and_symbols (System.Security.Cryptography.Native)
install_library_and_symbols (System.Security.Cryptography.Native.OpenSsl)

Some files were not shown because too many files have changed in this diff Show More