@@ -1464,8 +1464,9 @@ bool mmap::open(const char *path) {
14641464 auto wpath = u8string_to_wstring(path);
14651465 if (wpath.empty()) { return false; }
14661466
1467- hFile_ = ::CreateFile2(wpath.c_str(), GENERIC_READ, FILE_SHARE_READ,
1468- OPEN_EXISTING, NULL);
1467+ hFile_ =
1468+ ::CreateFile2(wpath.c_str(), GENERIC_READ,
1469+ FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING, NULL);
14691470
14701471 if (hFile_ == INVALID_HANDLE_VALUE) { return false; }
14711472
@@ -2052,56 +2053,50 @@ int getaddrinfo_with_timeout(const char *node, const char *service,
20522053 return 0;
20532054#elif defined(_GNU_SOURCE) && defined(__GLIBC__) && \
20542055 (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2))
2055- // Linux implementation using getaddrinfo_a for asynchronous DNS resolution
2056- struct gaicb request;
2056+ // #2431: gai_cancel() is non-blocking and may return EAI_NOTCANCELED while
2057+ // the resolver worker still references the stack-local gaicb. The cancel
2058+ // path therefore waits (gai_suspend with no timeout) for the worker to
2059+ // actually finish before letting the stack frame go. The trade-off is that
2060+ // a wedged DNS server can hold this thread for the system resolver timeout
2061+ // (~30s by default) past the caller's connection timeout.
2062+ struct gaicb request {};
20572063 struct gaicb *requests[1] = {&request};
2058- struct sigevent sevp;
2059- struct timespec timeout;
2064+ struct sigevent sevp {};
2065+ struct timespec timeout {
2066+ timeout_sec, 0
2067+ };
20602068
2061- // Initialize the request structure
2062- memset(&request, 0, sizeof(request));
20632069 request.ar_name = node;
20642070 request.ar_service = service;
20652071 request.ar_request = hints;
2066-
2067- // Set up timeout
2068- timeout.tv_sec = timeout_sec;
2069- timeout.tv_nsec = 0;
2070-
2071- // Initialize sigevent structure (not used, but required)
2072- memset(&sevp, 0, sizeof(sevp));
20732072 sevp.sigev_notify = SIGEV_NONE;
20742073
2075- // Start asynchronous resolution
2076- int start_result = getaddrinfo_a(GAI_NOWAIT, requests, 1, &sevp);
2077- if (start_result != 0) { return start_result; }
2074+ int rc = getaddrinfo_a(GAI_NOWAIT, requests, 1, &sevp);
2075+ if (rc != 0) { return rc; }
20782076
2079- // Wait for completion with timeout
2080- int wait_result =
2081- gai_suspend((const struct gaicb *const *)requests, 1, &timeout);
2077+ auto cleanup = scope_exit([&] {
2078+ if (request.ar_result) { freeaddrinfo(request.ar_result); }
2079+ });
2080+
2081+ int wait_result = gai_suspend(requests, 1, &timeout);
20822082
20832083 if (wait_result == 0 || wait_result == EAI_ALLDONE) {
2084- // Completed successfully, get the result
20852084 int gai_result = gai_error(&request);
20862085 if (gai_result == 0) {
20872086 *res = request.ar_result;
2087+ request.ar_result = nullptr;
20882088 return 0;
2089- } else {
2090- // Clean up on error
2091- if (request.ar_result) { freeaddrinfo(request.ar_result); }
2092- return gai_result;
20932089 }
2094- } else if (wait_result == EAI_AGAIN) {
2095- // Timeout occurred, cancel the request
2096- gai_cancel(&request);
2097- return EAI_AGAIN;
2098- } else {
2099- // Other error occurred
2100- gai_cancel(&request);
2101- return wait_result;
2090+ return gai_result;
2091+ }
2092+
2093+ gai_cancel(&request);
2094+ while (gai_error(&request) == EAI_INPROGRESS) {
2095+ gai_suspend(requests, 1, nullptr);
21022096 }
2097+ return wait_result;
21032098#else
2104- // Fallback implementation using thread-based timeout for other Unix systems
2099+ // Fallback implementation using thread-based timeout for other Unix systems.
21052100
21062101 struct GetAddrInfoState {
21072102 ~GetAddrInfoState() {
@@ -14142,6 +14137,9 @@ ssize_t read(session_t session, void *buf, size_t len, TlsError &err) {
1414214137 err.code = impl::map_mbedtls_error(ret, err.sys_errno);
1414314138 err.backend_code = static_cast<uint64_t>(-ret);
1414414139 impl::mbedtls_last_error() = ret;
14140+ // mbedTLS signals a clean close_notify via a negative error code rather
14141+ // than 0; surface it as a clean EOF the way OpenSSL/wolfSSL do.
14142+ if (err.code == ErrorCode::PeerClosed) { return 0; }
1414514143 return -1;
1414614144}
1414714145
0 commit comments