Skip to content

Commit f4ae905

Browse files
gfoidlVSadov
andauthored
NameResolutionPal.Unix enabled async name resolution (dotnet#34633)
* Native implementation * Native tests * Managed implementation * Managed tests * Revert Interop.GetHostName change -- it's needed at other places too So this change was a bad idea ;-) * Fixed builds failures due to "unused parameter" * Native: move struct addrinfo hint from stack-alloc to heap-alloc Before I didn't last the async operation as it was on the stack. Now it's part of the GetAddrInfoAsyncState which gets heap allocted, so it last. I'm not sure if addrinfo needs to last the async operation, as the native tests pass either way. This change makes it more correct, nevertheless. * PR feedback * Fixed leak in tests.c according to valgrind's run * Fixed bug due to marshalled string argument * More managed PalTests * Revert "Native tests" This reverts commit 8c955bc and d7cb2be. * Handle the case of HostName="" and tests for this * Use flexible array member to hold the address in struct state Cf. dotnet#34633 (comment) * Nits in native layer Cf. dotnet#34633 (comment) * Fixed native merge conflict + added AddressFamily-handling * Fixed managed merge conflicts + added AddressFamily-handling * Updated NameResolutionPalTests for AddressFamily * Removed EnsureSocketsAreInitialized On Unix this was a nop anyway, dotnet#43284 removed it from Windows. * Fixed bug at native side Seems like "hint" must last the async operation, so stack-only won't do it. Tests will crash with ``` The active test run was aborted. Reason: Test host process crashed : .../runtime/src/libraries/Native/Unix/System.Native/pal_networking.c (315): error -7: Unknown AddrInfo error flag. Unknown error -7 (0 failed) ``` If put into the heap, it succeeds. * Refactor setting of the address family into TrySetAddressFamily * Fixed unused parameter warning / failure * Little cleanup * Fixed (unrelated) test failures Cf. dotnet#34633 (comment) * Made LoggingTest async instead of GetAwaiter().GetResult() * Use function pointer * Use OperatinngSystem instead of RuntimeInformation in tests * PR Feedback for CMake * Update src/libraries/Native/Unix/System.Native/extra_libs.cmake Co-authored-by: Günther Foidl <gue@korporal.at> * Revert "Update src/libraries/Native/Unix/System.Native/extra_libs.cmake" This reverts commit fa9c6f9. * Another to build single file host Based on dotnet#34633 (comment) * Test for !Windows instead excluding several Unix-flavors Cf. dotnet#34633 (comment) Co-authored-by: Vladimir Sadov <vsadov@microsoft.com>
1 parent 82a2cda commit f4ae905

File tree

12 files changed

+723
-129
lines changed

12 files changed

+723
-129
lines changed

src/installer/corehost/cli/apphost/static/configure.cmake

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
include(CheckIncludeFiles)
2+
include(CMakePushCheckState)
23

34
check_include_files(
45
GSS/GSS.h
@@ -10,3 +11,16 @@ if (HeimdalGssApi)
1011
gssapi/gssapi.h
1112
HAVE_HEIMDAL_HEADERS)
1213
endif()
14+
15+
if (CLR_CMAKE_TARGET_LINUX)
16+
cmake_push_check_state(RESET)
17+
set (CMAKE_REQUIRED_DEFINITIONS "-D_GNU_SOURCE")
18+
set (CMAKE_REQUIRED_LIBRARIES "-lanl")
19+
20+
check_symbol_exists(
21+
getaddrinfo_a
22+
netdb.h
23+
HAVE_GETADDRINFO_A)
24+
25+
cmake_pop_check_state()
26+
endif ()

src/libraries/Common/src/Interop/Unix/System.Native/Interop.HostEntry.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
using System;
4+
using System.Net.Sockets;
55
using System.Runtime.InteropServices;
66

77
internal static partial class Interop
@@ -32,8 +32,18 @@ internal unsafe struct HostEntry
3232
internal int IPAddressCount; // Number of IP addresses in the list
3333
}
3434

35+
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_PlatformSupportsGetAddrInfoAsync")]
36+
internal static extern bool PlatformSupportsGetAddrInfoAsync();
37+
3538
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetHostEntryForName")]
36-
internal static extern unsafe int GetHostEntryForName(string address, System.Net.Sockets.AddressFamily family, HostEntry* entry);
39+
internal static extern unsafe int GetHostEntryForName(string address, AddressFamily family, HostEntry* entry);
40+
41+
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetHostEntryForNameAsync")]
42+
internal static extern unsafe int GetHostEntryForNameAsync(
43+
string address,
44+
AddressFamily family,
45+
HostEntry* entry,
46+
delegate* unmanaged<HostEntry*, int, void> callback);
3747

3848
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_FreeHostEntry")]
3949
internal static extern unsafe void FreeHostEntry(HostEntry* entry);

src/libraries/Native/Unix/Common/pal_config.h.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#cmakedefine01 HAVE_F_FULLFSYNC
1111
#cmakedefine01 HAVE_O_CLOEXEC
1212
#cmakedefine01 HAVE_GETIFADDRS
13+
#cmakedefine01 HAVE_GETADDRINFO_A
1314
#cmakedefine01 HAVE_UTSNAME_DOMAINNAME
1415
#cmakedefine01 HAVE_STAT64
1516
#cmakedefine01 HAVE_FORK

src/libraries/Native/Unix/System.Native/entrypoints.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,9 @@ static const Entry s_sysNative[] =
115115
DllImportEntry(SystemNative_ReadEvents)
116116
DllImportEntry(SystemNative_CreateNetworkChangeListenerSocket)
117117
DllImportEntry(SystemNative_CloseNetworkChangeListenerSocket)
118+
DllImportEntry(SystemNative_PlatformSupportsGetAddrInfoAsync)
118119
DllImportEntry(SystemNative_GetHostEntryForName)
120+
DllImportEntry(SystemNative_GetHostEntryForNameAsync)
119121
DllImportEntry(SystemNative_FreeHostEntry)
120122
DllImportEntry(SystemNative_GetNameInfo)
121123
DllImportEntry(SystemNative_GetDomainName)

src/libraries/Native/Unix/System.Native/extra_libs.cmake

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,8 @@ macro(append_extra_system_libs NativeLibsExtra)
1313
if (CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS)
1414
list(APPEND ${NativeLibsExtra} "-framework Foundation")
1515
endif ()
16+
17+
if (CLR_CMAKE_TARGET_LINUX AND HAVE_GETADDRINFO_A)
18+
list(APPEND ${NativeLibsExtra} anl)
19+
endif ()
1620
endmacro()

src/libraries/Native/Unix/System.Native/pal_networking.c

Lines changed: 176 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@
6060
#if HAVE_LINUX_CAN_H
6161
#include <linux/can.h>
6262
#endif
63+
#if HAVE_GETADDRINFO_A
64+
#include <signal.h>
65+
#include <stdatomic.h>
66+
#endif
6367
#if HAVE_SYS_FILIO_H
6468
#include <sys/filio.h>
6569
#endif
@@ -335,37 +339,14 @@ static int32_t CopySockAddrToIPAddress(sockaddr* addr, sa_family_t family, IPAdd
335339
return -1;
336340
}
337341

338-
int32_t SystemNative_GetHostEntryForName(const uint8_t* address, int32_t addressFamily, HostEntry* entry)
342+
static int32_t GetHostEntries(const uint8_t* address, struct addrinfo* info, HostEntry* entry)
339343
{
340-
if (address == NULL || entry == NULL)
341-
{
342-
return GetAddrInfoErrorFlags_EAI_BADARG;
343-
}
344-
345344
int32_t ret = GetAddrInfoErrorFlags_EAI_SUCCESS;
346345

347-
struct addrinfo* info = NULL;
348346
#if HAVE_GETIFADDRS
349347
struct ifaddrs* addrs = NULL;
350348
#endif
351349

352-
sa_family_t platformFamily;
353-
if (!TryConvertAddressFamilyPalToPlatform(addressFamily, &platformFamily))
354-
{
355-
return GetAddrInfoErrorFlags_EAI_FAMILY;
356-
}
357-
358-
struct addrinfo hint;
359-
memset(&hint, 0, sizeof(struct addrinfo));
360-
hint.ai_flags = AI_CANONNAME;
361-
hint.ai_family = platformFamily;
362-
363-
int result = getaddrinfo((const char*)address, NULL, &hint, &info);
364-
if (result != 0)
365-
{
366-
return ConvertGetAddrInfoAndGetNameInfoErrorsToPal(result);
367-
}
368-
369350
entry->CanonicalName = NULL;
370351
entry->Aliases = NULL;
371352
entry->IPAddressList = NULL;
@@ -393,7 +374,8 @@ int32_t SystemNative_GetHostEntryForName(const uint8_t* address, int32_t address
393374

394375
#if HAVE_GETIFADDRS
395376
char name[_POSIX_HOST_NAME_MAX];
396-
result = gethostname((char*)name, _POSIX_HOST_NAME_MAX);
377+
378+
int result = gethostname((char*)name, _POSIX_HOST_NAME_MAX);
397379

398380
bool includeIPv4Loopback = true;
399381
bool includeIPv6Loopback = true;
@@ -443,6 +425,8 @@ int32_t SystemNative_GetHostEntryForName(const uint8_t* address, int32_t address
443425
}
444426
}
445427
}
428+
#else
429+
(void)address;
446430
#endif
447431

448432
if (entry->IPAddressCount > 0)
@@ -519,6 +503,166 @@ int32_t SystemNative_GetHostEntryForName(const uint8_t* address, int32_t address
519503
return ret;
520504
}
521505

506+
#if HAVE_GETADDRINFO_A
507+
struct GetAddrInfoAsyncState
508+
{
509+
struct gaicb gai_request;
510+
struct gaicb* gai_requests;
511+
struct sigevent sigevent;
512+
513+
struct addrinfo hint;
514+
HostEntry* entry;
515+
GetHostEntryForNameCallback callback;
516+
char address[];
517+
};
518+
519+
static void GetHostEntryForNameAsyncComplete(sigval_t context)
520+
{
521+
struct GetAddrInfoAsyncState* state = (struct GetAddrInfoAsyncState*)context.sival_ptr;
522+
523+
atomic_thread_fence(memory_order_acquire);
524+
525+
GetHostEntryForNameCallback callback = state->callback;
526+
527+
int ret = ConvertGetAddrInfoAndGetNameInfoErrorsToPal(gai_error(&state->gai_request));
528+
529+
if (ret == 0)
530+
{
531+
const uint8_t* address = (const uint8_t*)state->address;
532+
struct addrinfo* info = state->gai_request.ar_result;
533+
534+
ret = GetHostEntries(address, info, state->entry);
535+
}
536+
537+
assert(callback != NULL);
538+
callback(state->entry, ret);
539+
540+
free(state);
541+
}
542+
#endif
543+
544+
static bool TrySetAddressFamily(int32_t addressFamily, struct addrinfo* hint)
545+
{
546+
sa_family_t platformFamily;
547+
if (!TryConvertAddressFamilyPalToPlatform(addressFamily, &platformFamily))
548+
{
549+
return false;
550+
}
551+
552+
memset(hint, 0, sizeof(struct addrinfo));
553+
554+
hint->ai_flags = AI_CANONNAME;
555+
hint->ai_family = platformFamily;
556+
557+
return true;
558+
}
559+
560+
int32_t SystemNative_PlatformSupportsGetAddrInfoAsync()
561+
{
562+
return HAVE_GETADDRINFO_A;
563+
}
564+
565+
int32_t SystemNative_GetHostEntryForName(const uint8_t* address, int32_t addressFamily, HostEntry* entry)
566+
{
567+
if (address == NULL || entry == NULL)
568+
{
569+
return GetAddrInfoErrorFlags_EAI_BADARG;
570+
}
571+
572+
struct addrinfo hint;
573+
if (!TrySetAddressFamily(addressFamily, &hint))
574+
{
575+
return GetAddrInfoErrorFlags_EAI_FAMILY;
576+
}
577+
578+
struct addrinfo* info = NULL;
579+
580+
int result = getaddrinfo((const char*)address, NULL, &hint, &info);
581+
if (result != 0)
582+
{
583+
return ConvertGetAddrInfoAndGetNameInfoErrorsToPal(result);
584+
}
585+
586+
return GetHostEntries(address, info, entry);
587+
}
588+
589+
int32_t SystemNative_GetHostEntryForNameAsync(const uint8_t* address, int32_t addressFamily, HostEntry* entry, GetHostEntryForNameCallback callback)
590+
{
591+
#if HAVE_GETADDRINFO_A
592+
if (address == NULL || entry == NULL)
593+
{
594+
return GetAddrInfoErrorFlags_EAI_BADARG;
595+
}
596+
597+
size_t addrlen = strlen((const char*)address);
598+
599+
if (addrlen > _POSIX_HOST_NAME_MAX)
600+
{
601+
return GetAddrInfoErrorFlags_EAI_BADARG;
602+
}
603+
604+
sa_family_t platformFamily;
605+
if (!TryConvertAddressFamilyPalToPlatform(addressFamily, &platformFamily))
606+
{
607+
return GetAddrInfoErrorFlags_EAI_FAMILY;
608+
}
609+
610+
struct GetAddrInfoAsyncState* state = malloc(sizeof(*state) + addrlen + 1);
611+
612+
if (state == NULL)
613+
{
614+
return GetAddrInfoErrorFlags_EAI_MEMORY;
615+
}
616+
617+
if (!TrySetAddressFamily(addressFamily, &state->hint))
618+
{
619+
free(state);
620+
return GetAddrInfoErrorFlags_EAI_FAMILY;
621+
}
622+
623+
memcpy(state->address, address, addrlen + 1);
624+
625+
*state = (struct GetAddrInfoAsyncState) {
626+
.gai_request = {
627+
.ar_name = state->address,
628+
.ar_service = NULL,
629+
.ar_request = &state->hint,
630+
.ar_result = NULL
631+
},
632+
.gai_requests = &state->gai_request,
633+
.sigevent = {
634+
.sigev_notify = SIGEV_THREAD,
635+
.sigev_value = {
636+
.sival_ptr = state
637+
},
638+
.sigev_notify_function = GetHostEntryForNameAsyncComplete
639+
},
640+
.entry = entry,
641+
.callback = callback
642+
};
643+
644+
atomic_thread_fence(memory_order_release);
645+
646+
int32_t result = getaddrinfo_a(GAI_NOWAIT, &state->gai_requests, 1, &state->sigevent);
647+
648+
if (result != 0)
649+
{
650+
free(state);
651+
return ConvertGetAddrInfoAndGetNameInfoErrorsToPal(result);
652+
}
653+
654+
return result;
655+
#else
656+
(void)address;
657+
(void)addressFamily;
658+
(void)entry;
659+
(void)callback;
660+
661+
// GetHostEntryForNameAsync is not supported on this platform.
662+
return -1;
663+
#endif
664+
}
665+
522666
void SystemNative_FreeHostEntry(HostEntry* entry)
523667
{
524668
if (entry != NULL)
@@ -555,13 +699,13 @@ static inline NativeFlagsType ConvertGetNameInfoFlagsToNative(int32_t flags)
555699
}
556700

557701
int32_t SystemNative_GetNameInfo(const uint8_t* address,
558-
int32_t addressLength,
559-
int8_t isIPv6,
560-
uint8_t* host,
561-
int32_t hostLength,
562-
uint8_t* service,
563-
int32_t serviceLength,
564-
int32_t flags)
702+
int32_t addressLength,
703+
int8_t isIPv6,
704+
uint8_t* host,
705+
int32_t hostLength,
706+
uint8_t* service,
707+
int32_t serviceLength,
708+
int32_t flags)
565709
{
566710
assert(address != NULL);
567711
assert(addressLength > 0);

src/libraries/Native/Unix/System.Native/pal_networking.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,8 +301,16 @@ typedef struct
301301
uint32_t Padding; // Pad out to 8-byte alignment
302302
} SocketEvent;
303303

304+
PALEXPORT int32_t SystemNative_PlatformSupportsGetAddrInfoAsync(void);
305+
304306
PALEXPORT int32_t SystemNative_GetHostEntryForName(const uint8_t* address, int32_t addressFamily, HostEntry* entry);
305307

308+
typedef void (*GetHostEntryForNameCallback)(HostEntry* entry, int status);
309+
PALEXPORT int32_t SystemNative_GetHostEntryForNameAsync(const uint8_t* address,
310+
int32_t addressFamily,
311+
HostEntry* entry,
312+
GetHostEntryForNameCallback callback);
313+
306314
PALEXPORT void SystemNative_FreeHostEntry(HostEntry* entry);
307315

308316

src/libraries/Native/Unix/configure.cmake

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ include(CheckPrototypeDefinition)
66
include(CheckStructHasMember)
77
include(CheckSymbolExists)
88
include(CheckTypeSize)
9+
include(CMakePushCheckState)
910

1011
# CMP0075 Include file check macros honor CMAKE_REQUIRED_LIBRARIES.
1112
if(POLICY CMP0075)
@@ -900,6 +901,19 @@ check_symbol_exists(
900901
HAVE_INOTIFY_RM_WATCH)
901902
set (CMAKE_REQUIRED_LIBRARIES ${PREVIOUS_CMAKE_REQUIRED_LIBRARIES})
902903

904+
if (CLR_CMAKE_TARGET_LINUX)
905+
cmake_push_check_state(RESET)
906+
set (CMAKE_REQUIRED_DEFINITIONS "-D_GNU_SOURCE")
907+
set (CMAKE_REQUIRED_LIBRARIES "-lanl")
908+
909+
check_symbol_exists(
910+
getaddrinfo_a
911+
netdb.h
912+
HAVE_GETADDRINFO_A)
913+
914+
cmake_pop_check_state()
915+
endif ()
916+
903917
set (HAVE_INOTIFY 0)
904918
if (HAVE_INOTIFY_INIT AND HAVE_INOTIFY_ADD_WATCH AND HAVE_INOTIFY_RM_WATCH)
905919
set (HAVE_INOTIFY 1)

0 commit comments

Comments
 (0)