|
|
@@ -5905,58 +5905,17 @@ inline int getaddrinfo_with_timeout(const char *node, const char *service,
|
|
|
|
|
|
*res = result_addrinfo;
|
|
|
return 0;
|
|
|
-#elif defined(_GNU_SOURCE) && defined(__GLIBC__) && \
|
|
|
- (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2))
|
|
|
- // Linux implementation using getaddrinfo_a for asynchronous DNS resolution
|
|
|
- struct gaicb request;
|
|
|
- struct gaicb *requests[1] = {&request};
|
|
|
- struct sigevent sevp;
|
|
|
- struct timespec timeout;
|
|
|
-
|
|
|
- // Initialize the request structure
|
|
|
- memset(&request, 0, sizeof(request));
|
|
|
- request.ar_name = node;
|
|
|
- request.ar_service = service;
|
|
|
- request.ar_request = hints;
|
|
|
-
|
|
|
- // Set up timeout
|
|
|
- timeout.tv_sec = timeout_sec;
|
|
|
- timeout.tv_nsec = 0;
|
|
|
-
|
|
|
- // Initialize sigevent structure (not used, but required)
|
|
|
- memset(&sevp, 0, sizeof(sevp));
|
|
|
- sevp.sigev_notify = SIGEV_NONE;
|
|
|
-
|
|
|
- // Start asynchronous resolution
|
|
|
- int start_result = getaddrinfo_a(GAI_NOWAIT, requests, 1, &sevp);
|
|
|
- if (start_result != 0) { return start_result; }
|
|
|
-
|
|
|
- // Wait for completion with timeout
|
|
|
- int wait_result =
|
|
|
- gai_suspend((const struct gaicb *const *)requests, 1, &timeout);
|
|
|
-
|
|
|
- if (wait_result == 0 || wait_result == EAI_ALLDONE) {
|
|
|
- // Completed successfully, get the result
|
|
|
- int gai_result = gai_error(&request);
|
|
|
- if (gai_result == 0) {
|
|
|
- *res = request.ar_result;
|
|
|
- return 0;
|
|
|
- } else {
|
|
|
- // Clean up on error
|
|
|
- if (request.ar_result) { freeaddrinfo(request.ar_result); }
|
|
|
- return gai_result;
|
|
|
- }
|
|
|
- } else if (wait_result == EAI_AGAIN) {
|
|
|
- // Timeout occurred, cancel the request
|
|
|
- gai_cancel(&request);
|
|
|
- return EAI_AGAIN;
|
|
|
- } else {
|
|
|
- // Other error occurred
|
|
|
- gai_cancel(&request);
|
|
|
- return wait_result;
|
|
|
- }
|
|
|
#else
|
|
|
- // Fallback implementation using thread-based timeout for other Unix systems
|
|
|
+ // Fallback implementation using thread-based timeout for other Unix systems.
|
|
|
+ //
|
|
|
+ // The previous Linux/glibc path used getaddrinfo_a(GAI_NOWAIT) with a
|
|
|
+ // stack-local gaicb. On timeout it called gai_cancel(), which is non-
|
|
|
+ // blocking and may return EAI_NOTCANCELED -- the resolver worker would
|
|
|
+ // then write back to the destroyed stack frame after this function had
|
|
|
+ // already returned (#2431). The std::thread + shared_ptr fallback below
|
|
|
+ // is correct for the same reason it works on other platforms: the
|
|
|
+ // worker captures shared ownership of the state, so it stays alive as
|
|
|
+ // long as anyone (caller or worker) still holds a reference.
|
|
|
|
|
|
struct GetAddrInfoState {
|
|
|
~GetAddrInfoState() {
|