NetBSD Problem Report #57932

From  Tue Feb 13 19:17:06 2024
Return-Path: <>
Received: from ( [])
	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits))
	(Client CN "", Issuer " CA" (not verified))
	by (Postfix) with ESMTPS id B98F01A9238
	for <>; Tue, 13 Feb 2024 19:17:06 +0000 (UTC)
Message-Id: <>
Date: Tue, 13 Feb 2024 19:17:05 +0000 (UTC)
Subject: getaddrinfo and other nsswitch.conf/nsdispatch front ends should support asynchronous operation
X-Send-Pr-Version: www-1.0

>Number:         57932
>Category:       lib
>Synopsis:       getaddrinfo and other nsswitch.conf/nsdispatch front ends should support asynchronous operation
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    lib-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Feb 13 19:20:00 +0000 2024
>Originator:     Taylor R Campbell
>Release:        current, 10, 9, 8, 7, 6, ...
The NsswitchBSD Foundation
nsdispatch(3) and its front ends like getaddrinfo(3) are all synchronous: they block until they have a complete result.

This means that in order for a process to do name service resolution in the background while remaining interactive, it is essentially required either

(a) to run getaddrinfo(3) in a separate thread; or
(b) to implement its own name resolution, bypassing nsswitch.conf and maybe parsing resolv.conf or bypassing resolv.conf.

Both of these options are bad: thread creation is probably much more expensive than getaddrinfo(3) needs to be, and if you pool threads, slow requests can needlessly hold up fast requests when the pool runs out; and bypassing nsswitch.conf or resolv.conf means losing out on things like /etc/hosts, mdnsd, and resolv.conf options.
try to use getaddrinfo(3) in interactive programs
Yes, please!

Here's a candidate API draft:

struct gettingaddrinfo;

struct gettingaddrinfo *gettingaddrinfo_begin(const char *, const char *,
    const struct addrinfo *);
bool gettingaddrinfo_done(struct gettingaddrinfo *, int *, struct addrinfo **);
int gettingaddrinfo_fd(const struct gettingaddrinfo *);
bool gettingaddrinfo_reading(const struct gettingaddrinfo *);
bool gettingaddrinfo_writing(const struct gettingaddrinfo *);
void gettingaddrinfo_step(struct gettingaddrinfo *);
void gettingaddrinfo_end(struct gettingaddrinfo *);

You could use this to implement getaddrinfo like so:

getaddrinfo(const char *hostname, const char *servname,
    const struct addrinfo *hints, struct addrinfo **aip)
	struct gettingaddrinfo *aing;
	int error;

	aing = gettingaddrinfo_begin(hostname, servname, hints);
	while (!gettingaddrinfo_done(aing, &error, aip)) {
		struct pollfd pfd = {
			.pfd = gettingaddrinfo_fd(aing),
			.events = 0,
		if (gettingaddrinfo_reading(aing)) |= POLLIN;
		if (gettingaddrinfo_writing(aing)) |= POLLOUT;
		if (poll(&pfd, 1, INFTIM) == -1) {
			error = EAI_SYSTEM;
			*aip = NULL;

	return error;

Of course, you can also multiplex the poll (or select or kqueue or what have you) with any other asynchronous I/O operations you're doing at the same time, and only call gettingaddrinfo_step when the gettingaddrinfo fd is ready for read/write as appropriate according to pfd.revents.

The painful part here will be (a) touching the res(3) code to split it up into asynchronous parts, and (b) adapting all the nsdispatch logic to handle asynchronous operation.

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.47 2022/09/11 19:34:41 kim Exp $
$NetBSD:,v 1.9 2014/08/02 14:16:04 spz Exp $
Copyright © 1994-2024 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.