From 5eaf9ea308debdeb9854f95f75b2d5bd414f8b0f Mon Sep 17 00:00:00 2001 From: Guy Bedford Date: Thu, 8 Oct 2026 15:28:13 -0700 Subject: [PATCH] Make getaddrinfo an asynchronous lookup with promise and callback variants emscripten_dns_lookup(node, service, hints) is the getaddrinfo body as one __async: ['promise', 'callback'] function: it resolves to a newly allocated addrinfo list (or a negative EAI_* code), synchronously for numeric addresses and errors, and under NODERAWSOCKETS after a node:dns lookup for a hostname, or EAI_AGAIN where the caller cannot wait. getaddrinfo() itself becomes a C wrapper over it; the hand-written dispatch goes away. emscripten_dns_lookup_promise() and emscripten_dns_lookup_callback() are its variants, so a real DNS lookup can be awaited without blocking from any stack: as an em_promise_t, or a callback on the calling thread. --- ChangeLog.md | 4 + .../docs/api_reference/emscripten.h.rst | 21 +++ src/lib/libcore.js | 141 +++++++++--------- src/lib/libsigs.js | 4 +- system/include/emscripten/em_types.h | 1 + system/include/emscripten/emscripten.h | 14 ++ system/lib/libc/getaddrinfo.c | 14 ++ .../test_codesize_hello_dylink_all.json | 12 +- test/sockets/test_dns_async.c | 132 ++++++++++++++++ test/test_other.py | 5 + test/test_sockets_node.py | 6 + tools/native_sigs.py | 1 + tools/system_libs.py | 5 + 13 files changed, 282 insertions(+), 78 deletions(-) create mode 100644 system/lib/libc/getaddrinfo.c create mode 100644 test/sockets/test_dns_async.c diff --git a/ChangeLog.md b/ChangeLog.md index 16001ddf1324c..74ce06218c6be 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -25,6 +25,10 @@ See docs/process.md for more on how version tagging works. - `MEMORY64=2` was marked as deprecated. (#27952) - The undocumented `FS.filesystems` object was removed. Replace things like `FS.filesystems['MEMFS']` with plain `MEMFS`. (#27940) +- Added `emscripten_dns_lookup_promise` and `emscripten_dns_lookup_callback`, + asynchronous variants of `getaddrinfo` completing through an `em_promise_t` + or a callback, so a real DNS lookup under `-sNODERAWSOCKETS` can be awaited + without blocking from any stack. 6.0.12 - 10/08/26 ----------------- diff --git a/site/source/docs/api_reference/emscripten.h.rst b/site/source/docs/api_reference/emscripten.h.rst index 87a680a412647..ff20f180aabf8 100644 --- a/site/source/docs/api_reference/emscripten.h.rst +++ b/site/source/docs/api_reference/emscripten.h.rst @@ -1605,6 +1605,27 @@ Functions arbitrary ``userData`` passed to this function. +.. c:function:: intptr_t emscripten_dns_lookup(const char *name, const char *service, const struct addrinfo *hints) + em_promise_t emscripten_dns_lookup_promise(const char *name, const char *service, const struct addrinfo *hints) + void emscripten_dns_lookup_callback(const char *name, const char *service, const struct addrinfo *hints, void (*callback)(bool err, intptr_t result, void *arg), void *arg) + + ``getaddrinfo()`` as one asynchronous lookup in three variants. Each + resolves to the head of a newly allocated ``addrinfo`` list (free it with + ``freeaddrinfo()``), or a negative ``EAI_*`` code. + + ``emscripten_dns_lookup()`` is synchronous and is what ``getaddrinfo()`` + calls: where the stack cannot wait for a real lookup (the main thread of a + build without ``ASYNCIFY``/JSPI under ``-sNODERAWSOCKETS``) it returns + ``EAI_AGAIN``. ``emscripten_dns_lookup_promise()`` returns an + ``em_promise_t`` (see ````) fulfilled with the result. + ``emscripten_dns_lookup_callback()`` calls ``callback(err, result, arg)`` + on the calling thread with it once the lookup completes, always after the + call has returned; a pending callback keeps the runtime alive, like a timer. + (``err`` is never set: a failed lookup is an ``EAI_*`` ``result``.) + + Without ``-sNODERAWSOCKETS`` every lookup completes synchronously. + + Unaligned types =============== diff --git a/src/lib/libcore.js b/src/lib/libcore.js index d0e79e4f09fe8..7700ffb16ce17 100644 --- a/src/lib/libcore.js +++ b/src/lib/libcore.js @@ -1002,36 +1002,15 @@ addToLibrary({ } }, - getaddrinfo__deps: ['$inetPton4', '$inetNtop4', '$inetPton6', '$inetNtop6', '$writeSockaddr', 'malloc', 'htonl', -#if NODERAWSOCKETS - '$nodeSockHelpers', -#else - '$DNS', -#endif -#if NODERAWSOCKETS && ASYNCIFY - '$Asyncify', -#endif - ], - getaddrinfo__proxy: 'sync', -#if NODERAWSOCKETS && (PTHREADS || ASYNCIFY) - // Returns an EAI_* code synchronously, or - for a hostname needing a real - // DNS lookup - a Promise of one, which a sync-proxied pthread awaits and - // ASYNCIFY/JSPI suspend on. - getaddrinfo__async: true, -#endif - getaddrinfo: (node, service, hint, out) => { - // Note getaddrinfo currently only returns a single addrinfo with ai_next defaulting to NULL. When NULL - // hints are specified or ai_family set to AF_UNSPEC or ai_socktype or ai_protocol set to 0 then we - // really should provide a linked list of suitable addrinfo values. - var addrs = []; + // Complete a getAddrInfo result: an EAI_* code (negative) is returned as is; + // a resolved descriptor is allocated as an addrinfo list (freed by + // freeaddrinfo) and its head returned. + $allocAddrInfo__internal: true, + $allocAddrInfo__deps: ['$inetNtop4', '$inetNtop6', '$writeSockaddr', 'malloc'], + $allocAddrInfo: (desc) => { + if (typeof desc === 'number') return desc; + var {type, proto, port} = desc; var canon = null; - var addr = 0; - var port = 0; - var flags = 0; - var family = {{{ cDefs.AF_UNSPEC }}}; - var type = 0; - var proto = 0; - var ai, last; function allocaddrinfo(family, type, proto, canon, addr, port) { var sa, salen, ai; @@ -1065,26 +1044,42 @@ addToLibrary({ return ai; } -#if NODERAWSOCKETS - // Resolve via node:dns (which honors the host's /etc/hosts), chaining one - // addrinfo per {family, addr} result into *out. - async function lookupHostname() { - var entries = await nodeSockHelpers.lookupHost(node, family); - if (typeof entries === 'number') return entries; - var head = 0, prev = 0; - for (var entry of entries) { - var ai = allocaddrinfo(entry.family, type, proto, null, entry.addr, port); - if (prev) { - {{{ makeSetValue('prev', C_STRUCTS.addrinfo.ai_next, 'ai', '*') }}}; - } else { - head = ai; - } - prev = ai; + var head = 0, prev = 0; + for (var {family, addr} of desc.entries) { + var ai = allocaddrinfo(family, type, proto, canon, addr, port); + if (prev) { + {{{ makeSetValue('prev', C_STRUCTS.addrinfo.ai_next, 'ai', '*') }}}; + } else { + head = ai; } - {{{ makeSetValue('out', '0', 'head', '*') }}}; - return 0; + prev = ai; } + return head; + }, + + // The getaddrinfo body, allocating nothing. Returns an EAI_* code or a + // descriptor {type, proto, port, entries: [{family, addr}]}. Under + // NODERAWSOCKETS a hostname needs an asynchronous node:dns lookup: the + // descriptor then has `lookup` instead of `entries`, an async function + // resolving to a code or entries, for the caller to wait on. + $getAddrInfo__internal: true, + $getAddrInfo__deps: ['$inetPton4', '$inetPton6', 'htonl', +#if NODERAWSOCKETS + '$nodeSockHelpers', +#else + '$DNS', #endif + ], + $getAddrInfo: (node, service, hint) => { + // Note getaddrinfo currently only returns a single addrinfo with ai_next defaulting to NULL. When NULL + // hints are specified or ai_family set to AF_UNSPEC or ai_socktype or ai_protocol set to 0 then we + // really should provide a linked list of suitable addrinfo values. + var addr = 0; + var port = 0; + var flags = 0; + var family = {{{ cDefs.AF_UNSPEC }}}; + var type = 0; + var proto = 0; if (hint) { flags = {{{ makeGetValue('hint', C_STRUCTS.addrinfo.ai_flags, 'i32') }}}; @@ -1154,9 +1149,7 @@ addToLibrary({ addr = [0, 0, 0, _htonl(1)]; } } - ai = allocaddrinfo(family, type, proto, null, addr, port); - {{{ makeSetValue('out', '0', 'ai', '*') }}}; - return 0; + return {type, proto, port, entries: [{family, addr}]}; } // @@ -1187,9 +1180,7 @@ addToLibrary({ } } if (addr != null) { - ai = allocaddrinfo(family, type, proto, node, addr, port); - {{{ makeSetValue('out', '0', 'ai', '*') }}}; - return 0; + return {type, proto, port, entries: [{family, addr}]}; } if (flags & {{{ cDefs.AI_NUMERICHOST }}}) { return {{{ cDefs.EAI_NONAME }}}; @@ -1199,23 +1190,11 @@ addToLibrary({ // try as a hostname // #if NODERAWSOCKETS - // The lookup is asynchronous, so only start it where the calling stack can - // wait on the Promise: a sync-proxied pthread (PROXY_SYNC_ASYNC) awaits it, - // ASYNCIFY/JSPI suspend on it. Otherwise (the event-loop thread itself) it - // must not start at all, since it would write to *out after we have - // returned. -#if PTHREADS - if (PThread.currentProxiedOperationCallerThread) return lookupHostname(); -#endif -#if ASYNCIFY - // handleAsync holds a runtime keepalive across the suspension, so a user - // callback completing meanwhile does not exit the runtime under main(). - // Everything above this point is pure, so the ASYNCIFY rewind re-running - // this body reaches handleAsync again and takes the stored result. - return Asyncify.handleAsync(lookupHostname); -#else - return {{{ cDefs.EAI_AGAIN }}}; -#endif + // node:dns honors the host's /etc/hosts. + return {type, proto, port, lookup: async () => { + var entries = await nodeSockHelpers.lookupHost(node, family); + return typeof entries === 'number' ? entries : {type, proto, port, entries}; + }}; #else // resolve the hostname to a temporary fake address node = DNS.lookup_name(node); @@ -1225,10 +1204,28 @@ addToLibrary({ } else if (family === {{{ cDefs.AF_INET6 }}}) { addr = [0, 0, _htonl(0xffff), addr]; } - ai = allocaddrinfo(family, type, proto, null, addr, port); - {{{ makeSetValue('out', '0', 'ai', '*') }}}; - return 0; + return {type, proto, port, entries: [{family, addr}]}; +#endif + }, + + // getaddrinfo() as one asynchronous body with variants: resolves to the + // head of a newly allocated addrinfo list (freed with freeaddrinfo), or an + // EAI_* code (negative). Numeric addresses and errors complete + // synchronously; under NODERAWSOCKETS a hostname awaits node:dns, or is + // EAI_AGAIN where the caller cannot wait. getaddrinfo() itself + // (system/lib/libc/getaddrinfo.c) calls the synchronous form. + emscripten_dns_lookup__deps: ['$getAddrInfo', '$allocAddrInfo'], + emscripten_dns_lookup__async: ['promise', 'callback'], + emscripten_dns_lookup__proxy: 'sync', + emscripten_dns_lookup: (node, service, hint, sync) => { + var desc = getAddrInfo(node, service, hint); +#if NODERAWSOCKETS + if (desc.lookup) { + if (sync) return {{{ cDefs.EAI_AGAIN }}}; + return desc.lookup().then(allocAddrInfo); + } #endif + return allocAddrInfo(desc); }, getnameinfo__deps: ['$readSockaddr', '$stringToUTF8', diff --git a/src/lib/libsigs.js b/src/lib/libsigs.js index 58cfc60863756..86cfb069146c7 100644 --- a/src/lib/libsigs.js +++ b/src/lib/libsigs.js @@ -641,6 +641,9 @@ sigs = { emscripten_destroy_audio_context__sig: 'vi', emscripten_destroy_web_audio_node__sig: 'vi', emscripten_destroy_worker__sig: 'vi', + emscripten_dns_lookup__sig: 'pppp', + emscripten_dns_lookup_callback__sig: 'vppppp', + emscripten_dns_lookup_promise__sig: 'pppp', emscripten_enter_soft_fullscreen__sig: 'ipp', emscripten_epoll_listener_add__sig: 'iipp', emscripten_epoll_listener_remove__sig: 'iipp', @@ -942,7 +945,6 @@ sigs = { fd_write__sig: 'iippp', filledEllipseColor__sig: 'ipiiiii', filledEllipseRGBA__sig: 'ipiiiiiiii', - getaddrinfo__sig: 'ipppp', getnameinfo__sig: 'ipipipii', getprotobyname__sig: 'pp', getprotobynumber__sig: 'pi', diff --git a/system/include/emscripten/em_types.h b/system/include/emscripten/em_types.h index eb4cb5ba9c25a..473ec217f8227 100644 --- a/system/include/emscripten/em_types.h +++ b/system/include/emscripten/em_types.h @@ -8,6 +8,7 @@ #pragma once #include +#include /* Typedefs */ diff --git a/system/include/emscripten/emscripten.h b/system/include/emscripten/emscripten.h index 43d2f2899dd0e..a838e4c8f953c 100644 --- a/system/include/emscripten/emscripten.h +++ b/system/include/emscripten/emscripten.h @@ -68,6 +68,20 @@ void emscripten_set_socket_connection_callback(void *userData, em_socket_callbac void emscripten_set_socket_message_callback(void *userData, em_socket_callback callback); void emscripten_set_socket_close_callback(void *userData, em_socket_callback callback); +// getaddrinfo() as one asynchronous lookup in three variants. Each resolves +// to the head of a newly allocated addrinfo list (free with freeaddrinfo()), +// or a (negative) EAI_* code. emscripten_dns_lookup() is synchronous (it is +// what getaddrinfo() calls): where the stack cannot wait for a real lookup - +// the main thread without ASYNCIFY/JSPI - it returns EAI_AGAIN. +// emscripten_dns_lookup_promise() returns an em_promise_t fulfilled with the +// result; emscripten_dns_lookup_callback() calls callback(err, result, arg) on +// the calling thread with it, after returning (err is never set: a failed +// lookup is an EAI_* result). +struct addrinfo; +intptr_t emscripten_dns_lookup(const char *name, const char *service, const struct addrinfo *hints); +em_promise_t emscripten_dns_lookup_promise(const char *name, const char *service, const struct addrinfo *hints); +void emscripten_dns_lookup_callback(const char *name, const char *service, const struct addrinfo *hints, void (*callback)(bool err, intptr_t result, void *arg), void *arg); + void _emscripten_push_main_loop_blocker(em_arg_callback_func func, void *arg, const char *name); void _emscripten_push_uncounted_main_loop_blocker(em_arg_callback_func func, void *arg, const char *name); #define emscripten_push_main_loop_blocker(func, arg) \ diff --git a/system/lib/libc/getaddrinfo.c b/system/lib/libc/getaddrinfo.c new file mode 100644 index 0000000000000..1bea195226887 --- /dev/null +++ b/system/lib/libc/getaddrinfo.c @@ -0,0 +1,14 @@ +// Emscripten-specific version of musl/src/network/getaddrinfo.c: the +// synchronous call variant of emscripten_dns_lookup (see libcore.js). + +#include +#include +#include + +int getaddrinfo(const char *restrict host, const char *restrict serv, const struct addrinfo *restrict hint, struct addrinfo **restrict res) +{ + intptr_t r = emscripten_dns_lookup(host, serv, hint); + if (r < 0) return r; + *res = (struct addrinfo*)r; + return 0; +} diff --git a/test/codesize/test_codesize_hello_dylink_all.json b/test/codesize/test_codesize_hello_dylink_all.json index 9550adcb9a40f..96be3b094b9a5 100644 --- a/test/codesize/test_codesize_hello_dylink_all.json +++ b/test/codesize/test_codesize_hello_dylink_all.json @@ -1,7 +1,7 @@ { - "a.out.js": 272568, - "a.out.nodebug.wasm": 588100, - "total": 860668, + "a.out.js": 272803, + "a.out.nodebug.wasm": 588158, + "total": 860961, "sent": [ "IMG_Init", "IMG_Load", @@ -466,6 +466,7 @@ "emscripten_date_now", "emscripten_debugger", "emscripten_destroy_worker", + "emscripten_dns_lookup", "emscripten_enter_soft_fullscreen", "emscripten_epoll_listener_add", "emscripten_epoll_listener_remove", @@ -1004,7 +1005,6 @@ "fd_write", "filledEllipseColor", "filledEllipseRGBA", - "getaddrinfo", "getnameinfo", "getprotobyname", "getprotobynumber", @@ -1838,6 +1838,7 @@ "env._tzset_js", "env.emscripten_asm_const_int", "env.emscripten_date_now", + "env.emscripten_dns_lookup", "env.emscripten_get_heap_max", "env.emscripten_get_now", "env.emscripten_promise_create", @@ -1847,7 +1848,6 @@ "env.emscripten_set_canvas_element_size", "env.emscripten_wget_data", "env.exit", - "env.getaddrinfo", "env.getnameinfo", "wasi_snapshot_preview1.clock_res_get", "wasi_snapshot_preview1.clock_time_get", @@ -2784,6 +2784,7 @@ "get_nprocs", "get_nprocs_conf", "get_phys_pages", + "getaddrinfo", "getc", "getc_unlocked", "getchar", @@ -4635,6 +4636,7 @@ "$get_nprocs", "$get_nprocs_conf", "$get_phys_pages", + "$getaddrinfo", "$getc_unlocked", "$getchar", "$getchar_unlocked", diff --git a/test/sockets/test_dns_async.c b/test/sockets/test_dns_async.c new file mode 100644 index 0000000000000..953b1db6b4373 --- /dev/null +++ b/test/sockets/test_dns_async.c @@ -0,0 +1,132 @@ +/* + * Copyright 2026 The Emscripten Authors. All rights reserved. + * Emscripten is available under two separate licenses, the MIT license and the + * University of Illinois/NCSA Open Source License. Both these licenses can be + * found in the LICENSE file. + * + * emscripten_dns_lookup_callback() / emscripten_dns_lookup_promise(): the + * call variants of getaddrinfo(). Numeric addresses and errors complete at + * once; a hostname completes after a real node:dns lookup under + * -sNODERAWSOCKETS (or at once with a fake address without it). Either way + * the result is delivered after the call returns, from any stack, including + * the main thread of a plain build where getaddrinfo() itself returns + * EAI_AGAIN. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int stage; +int returned; + +struct addrinfo hints = { .ai_family = AF_UNSPEC, .ai_socktype = SOCK_STREAM }; +struct addrinfo h4 = { .ai_family = AF_INET, .ai_socktype = SOCK_STREAM }; + +void check_v4(struct addrinfo* res, const char* addr) { + int n = 0; + for (struct addrinfo* ai = res; ai; ai = ai->ai_next) { + assert(ai->ai_socktype == SOCK_STREAM); + assert(ai->ai_protocol == IPPROTO_TCP); + assert(ai->ai_family == AF_INET); + struct sockaddr_in* sin = (struct sockaddr_in*)ai->ai_addr; + assert(ai->ai_addrlen == sizeof(*sin)); + assert(ntohs(sin->sin_port) == 80); + if (!addr || sin->sin_addr.s_addr == inet_addr(addr)) n++; + } + assert(n >= 1); +} + +void check_localhost(struct addrinfo* res) { +#ifdef REAL_DNS + check_v4(res, "127.0.0.1"); +#else + check_v4(res, NULL); +#endif + freeaddrinfo(res); +} + +em_promise_result_t fail(void** result, void* data, void* value) { + assert(0 && "lookup promise rejected"); +} + +em_promise_result_t on_resolved(void** result, void* data, void* value) { + assert(stage++ == 3); + check_localhost(value); + printf("done\n"); +#ifdef __EMSCRIPTEN_PTHREADS__ + exit(0); +#endif + return EM_PROMISE_FULFILL; +} + +void on_host(bool err, intptr_t result, void* arg) { + assert(stage++ == 2); + assert(!err); + assert(arg == &stage); + assert(result > 0); + check_localhost((struct addrinfo*)result); + + // The same lookup as a promise. + em_promise_t p = emscripten_dns_lookup_promise("localhost", "80", &h4); + em_promise_t next = emscripten_promise_then(p, on_resolved, fail, NULL); + emscripten_promise_destroy(p); + emscripten_promise_destroy(next); +} + +void on_error(bool err, intptr_t result, void* arg) { + assert(stage++ == 1); + assert(!err); + assert(result == EAI_SERVICE); + + // A hostname: pending until node:dns answers. + emscripten_dns_lookup_callback("localhost", "80", &h4, on_host, &stage); +#if defined(REAL_DNS) && !defined(__EMSCRIPTEN_PTHREADS__) + // Where the stack cannot wait, the synchronous form says so. + struct addrinfo* res; + assert(getaddrinfo("localhost", "80", &h4, &res) == EAI_AGAIN); +#endif +} + +void on_numeric(bool err, intptr_t result, void* arg) { + // A synchronous completion is still called back after the return. + assert(stage++ == 0); + assert(!err); + assert(returned); + struct addrinfo* res = (struct addrinfo*)result; + check_v4(res, "10.9.8.7"); + assert(!res->ai_next); + freeaddrinfo(res); + + // An error, as the (negative) EAI_* code. + emscripten_dns_lookup_callback("10.9.8.7", "http", &hints, on_error, NULL); +} + +int main() { + // The synchronous form completes for a numeric address and an error. + struct addrinfo* res = NULL; + assert(getaddrinfo("10.9.8.7", "80", &hints, &res) == 0); + check_v4(res, "10.9.8.7"); + freeaddrinfo(res); + assert(getaddrinfo("10.9.8.7", "http", &hints, &res) == EAI_SERVICE); + + // A pending callback holds the runtime. +#ifndef __EMSCRIPTEN_PTHREADS__ + assert(!emscripten_runtime_keepalive_check()); +#endif + emscripten_dns_lookup_callback("10.9.8.7", "80", &hints, on_numeric, NULL); + assert(emscripten_runtime_keepalive_check()); + returned = 1; + return 0; +} diff --git a/test/test_other.py b/test/test_other.py index 951bc3a077587..70c0284a565ba 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -11030,6 +11030,11 @@ def test_sin_zero(self): def test_getaddrinfo(self): self.do_runf('sockets/test_getaddrinfo.c', 'done\n') + def test_dns_lookup_async(self): + # emscripten_dns_lookup_callback/_promise without NODERAWSOCKETS: every + # lookup completes synchronously (fake addresses), delivered after return. + self.do_runf('sockets/test_dns_async.c', 'done\n', cflags=['-sEXIT_RUNTIME']) + def test_getnameinfo(self): self.do_runf('sockets/test_getnameinfo.c', 'done\n') diff --git a/test/test_sockets_node.py b/test/test_sockets_node.py index ad9517ebf8027..9b9a28cb0afae 100644 --- a/test/test_sockets_node.py +++ b/test/test_sockets_node.py @@ -244,6 +244,12 @@ def test_noderawsockets_dns_blocking_jspi(self): # Same, but getaddrinfo() suspends the wasm stack under JSPI. self.do_runf('sockets/test_dns.c', 'done\n', cflags=['-sNODERAWSOCKETS', '-sEXIT_RUNTIME']) + @also_with_proxy_to_pthread + def test_noderawsockets_dns_async(self): + # emscripten_dns_lookup_callback/_promise: a real node:dns lookup awaited + # through a callback or a promise, without blocking, from any stack. + self.do_runf('sockets/test_dns_async.c', 'done\n', cflags=['-sNODERAWSOCKETS', '-sEXIT_RUNTIME', '-DREAL_DNS']) + def test_noderawsockets_dns_blocking_asyncify(self): # Same, unwinding the wasm stack under ASYNCIFY. self.do_runf('sockets/test_dns.c', 'done\n', cflags=['-sNODERAWSOCKETS', '-sASYNCIFY', '-sEXIT_RUNTIME']) diff --git a/tools/native_sigs.py b/tools/native_sigs.py index c983d6f0c84a4..78d6a8651ed08 100644 --- a/tools/native_sigs.py +++ b/tools/native_sigs.py @@ -1001,6 +1001,7 @@ 'get_avphys_pages': 'p', 'get_current_dir_name': 'p', 'get_phys_pages': 'p', + 'getaddrinfo': '_pppp', 'getc': '_p', 'getc_unlocked': '_p', 'getcwd': 'ppp', diff --git a/tools/system_libs.py b/tools/system_libs.py index be253d25083f2..901f5afd85fd8 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -1550,6 +1550,11 @@ class libsockets(MuslInternalLibrary, MTLibrary): src_files = LIBC_SOCKETS cflags = ['-Os', '-fno-builtin', '-Wno-shift-op-parentheses'] + def get_files(self): + # getaddrinfo() is the synchronous form of emscripten_dns_lookup; with + # PROXY_POSIX_SOCKETS libsockets_proxy provides it instead. + return super().get_files() + [utils.path_from_root('system/lib/libc/getaddrinfo.c')] + def can_use(self): return super().can_use() and not settings.PROXY_POSIX_SOCKETS