1.\" $OpenBSD: asr_run.3,v 1.5 2022/03/31 17:27:15 naddy Exp $ 2.\" 3.\" Copyright (c) 2012-2014, Eric Faurot <eric@openbsd.org> 4.\" 5.\" Permission to use, copy, modify, and distribute this software for any 6.\" purpose with or without fee is hereby granted, provided that the above 7.\" copyright notice and this permission notice appear in all copies. 8.\" 9.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16.\" 17.Dd $Mdocdate: March 31 2022 $ 18.Dt ASR_RUN 3 19.Os 20.Sh NAME 21.Nm asr_run , 22.Nm asr_run_sync , 23.Nm asr_abort , 24.Nm asr_resolver_from_string , 25.Nm asr_resolver_free , 26.Nm res_send_async , 27.Nm res_query_async , 28.Nm res_search_async , 29.Nm getrrsetbyname_async , 30.Nm gethostbyname_async , 31.Nm gethostbyname2_async , 32.Nm gethostbyaddr_async , 33.Nm getnetbyname_async , 34.Nm getnetbyaddr_async , 35.Nm getaddrinfo_async , 36.Nm getnameinfo_async 37.Nd asynchronous resolver functions 38.Sh SYNOPSIS 39.In sys/types.h 40.In sys/socket.h 41.In netdb.h 42.In asr.h 43.Ft int 44.Fn asr_run "struct asr_query *aq" "struct asr_result *ar" 45.Ft int 46.Fn asr_run_sync "struct asr_query *aq" "struct asr_result *ar" 47.Ft void 48.Fn asr_abort "struct asr_query *aq" 49.Ft void * 50.Fn asr_resolver_from_string "const char *str" 51.Ft void 52.Fn asr_resolver_free "void *asr" 53.Ft struct asr_query * 54.Fn res_send_async "const unsigned char *pkt" "int pktlen" "void *asr" 55.Ft struct asr_query * 56.Fn res_query_async "const char *name" "int class" "int type" "void *asr" 57.Ft struct asr_query * 58.Fn res_search_async "const char *name" "int class" "int type" "void *asr" 59.Ft struct asr_query * 60.Fn getrrsetbyname_async "const char *hostname" "unsigned int rdclass" "unsigned int rdtype" "unsigned int flags" "void *asr" 61.Ft struct asr_query * 62.Fn gethostbyname_async "const char *name" "void *asr" 63.Ft struct asr_query * 64.Fn gethostbyname2_async "const char *name" "int af" "void *asr" 65.Ft struct asr_query * 66.Fn gethostbyaddr_async "const void *addr" "socklen_t len" "int af" "void *asr" 67.Ft struct asr_query * 68.Fn getnetbyname_async "const char *name" "void *asr" 69.Ft struct asr_query * 70.Fn getnetbyaddr_async "in_addr_t net" "int type" "void *asr" 71.Ft struct asr_query * 72.Fn getaddrinfo_async "const char *hostname" "const char *servname" "const struct addrinfo *hints" "void *asr" 73.Ft struct asr_query * 74.Fn getnameinfo_async "const struct sockaddr *sa" "socklen_t salen" "char *host" "size_t hostlen" "char *serv" "size_t servlen" "int flags" "void *asr" 75.Sh DESCRIPTION 76The 77.Nm asr 78functions provide a simple interface for asynchronous address 79resolution and nameserver querying. 80They should be used in place of the classical resolver functions 81of libc when blocking is not desirable. 82.Pp 83The principle of operation is as follows: 84All async requests are made against an 85.Nm asr 86context which basically defines a list of sources to query and a 87strategy to do so. 88The user creates a query through one of the dedicated functions, and 89gets a handle representing the internal query. 90A query is a state-machine that can be run to try to fulfill a 91particular request. 92This is done by calling in a generic API that performs the state 93transitions until it needs to give the control back to the user, 94either because a result is available, or because the next transition 95implies a blocking call (a file descriptor needs to be read from or 96written to). 97The user is responsible for dealing with the situation: either get 98the result, or wait until the fd conditions are met, and then call 99back into the resolving machinery when it is ready to proceed. 100.Pp 101The 102.Fn asr_run 103function drives the resolving process. 104It runs the asynchronous query represented by the 105.Fa aq 106handle until a result is available, or until it cannot continue 107without blocking. 108The results are returned to the user through the 109.Fa ar 110parameter, which must be a valid pointer to user allocated memory. 111.Fa ar 112is defined as: 113.Bd -literal 114struct asr_result { 115 116 /* Fields set if the query is not done yet (asr_run returns 0) */ 117 int ar_cond; /* ASR_WANT_READ or ASR_WANT_WRITE */ 118 int ar_fd; /* the fd waiting for io condition */ 119 int ar_timeout; /* time to wait for in milliseconds */ 120 121 /* Error fields. Depends on the query type. */ 122 int ar_errno; 123 int ar_h_errno; 124 int ar_gai_errno; 125 int ar_rrset_errno; 126 127 /* Result for res_*_async() calls */ 128 int ar_count; /* number of answers in the dns reply */ 129 int ar_rcode; /* response code in the dns reply */ 130 void *ar_data; /* raw reply packet (must be freed) */ 131 int ar_datalen; /* reply packet length */ 132 struct sockaddr_storage ar_ns; /* nameserver that responded */ 133 134 /* Result for other calls. Must be freed properly. */ 135 struct addrinfo *ar_addrinfo; 136 struct rrsetinfo *ar_rrsetinfo; 137 struct hostent *ar_hostent; 138 struct netent *ar_netent; 139}; 140.Ed 141.Pp 142The function returns one of the following values: 143.Bl -tag -width "0 " -offset indent 144.It 0 145The query cannot be processed further until a specific condition on a 146file descriptor becomes true. 147The following members of the 148.Fa ar 149structure are filled: 150.Pp 151.Bl -tag -width "ar_timeout " -compact 152.It Fa ar_cond 153one of ASR_WANT_READ or ASR_WANT_WRITE, 154.It Fa ar_fd 155the file descriptor waiting for an IO operation, 156.It Fa ar_timeout 157the amount of time to wait for in milliseconds. 158.El 159.Pp 160The caller is expected to call 161.Fn asr_run 162again once the condition holds or the timeout expires. 163.It 1 164The query is completed. 165The members relevant to the actual async query type are set accordingly, 166including error conditions. 167In any case, the query is cleared and its handle is invalidated. 168.El 169.Pp 170Note that although the query itself may fail (the error being properly reported 171in the 172.Fa ar 173structure), the 174.Fn asr_run 175function itself cannot fail and it always preserves errno. 176.Pp 177The 178.Fn asr_run_sync 179function is a wrapper around 180.Fn asr_run 181that handles the read/write conditions, thus falling back to a blocking 182interface. 183It only returns 1. 184It also preserves errno. 185.Pp 186The 187.Fn asr_abort 188function clears a running query. 189It can be called when the query is waiting on a file descriptor. 190Note that a completed query is already cleared when 191.Fn asr_run 192returns, so 193.Fn asr_abort 194must not be called in this case. 195.Pp 196The 197.Fn asr_resolver_from_string 198function constructs an asr context from a string that conforms to the 199.Xr resolv.conf 5 200file format. 201.Fn asr_resolver_free 202frees an asr context obtained from 203.Fn asr_resolver_from_string . 204.Pp 205The remaining functions are used to initiate different kinds of query 206on the 207.Fa asr 208resolver context. 209The specific operational details for each of them are described below. 210All functions return a handle to an internal query, or NULL if they could 211not allocate the necessary resources to initiate the query. 212All other errors (especially invalid parameters) are reported when calling 213.Fn asr_run . 214They usually have the same interface as an existing resolver function, with 215an additional 216.Ar asr 217argument, which specifies the context to use for this request. 218An 219.Ar asr 220argument of NULL will use the default context for the current thread. 221This is constructed from 222.Pa /etc/resolv.conf 223and takes care of reloading the file when it changes. 224.Pp 225The 226.Fn res_send_async , 227.Fn res_query_async 228and 229.Fn res_search_async 230functions are asynchronous versions of the standard libc resolver routines. 231Their interface is very similar, except that the response buffer is always 232allocated internally. 233The return value is found upon completion in the 234.Fa ar_datalen 235member of the response structure. 236In addition, the 237.Fa ar_ns 238structure contains the address of the DNS server that sent the response, 239.Fa ar_rcode 240contains the code returned by the server in the DNS response packet, and 241.Fa ar_count 242contains the number of answers in the packet. 243If a response is received, it is placed in a newly allocated buffer 244and returned as 245.Fa ar_data 246member. 247This buffer must be freed by the caller. 248On error, the 249.Fa ar_errno 250and 251.Fa ar_h_errno 252members are set accordingly. 253.Pp 254The 255.Fn getrrsetbyname_async 256function is an asynchronous version of 257.Xr getrrsetbyname 3 . 258Upon completion, the return code is found in 259.Fa ar_rrset_errno 260and the address to the newly allocated result set is set in 261.Fa ar_rrsetinfo . 262As for the blocking function, it must be freed by calling 263.Xr freerrset 3 . 264.Pp 265The 266.Fn gethostbyname_async , 267.Fn gethostbyname2_async 268and 269.Fn gethostbyaddr_async 270functions provide an asynchronous version of the network host entry functions. 271Upon completion, 272.Ar ar_h_errno 273is set and the resulting hostent address, if found, is set 274in the 275.Ar ar_hostent 276field. 277Note that unlike their blocking counterparts, these functions always return a 278pointer to newly allocated memory, which must be released by the caller using 279.Xr free 3 . 280.Pp 281Similarly, the 282.Fn getnetbyname_async 283and 284.Fn getnetbyaddr_async 285functions provide an asynchronous version of the network entry functions. 286Upon completion, 287.Ar ar_h_errno 288is set and the resulting netent address, if found, is set 289in the 290.Ar ar_netent 291field. 292The memory there is also allocated for the request, and it must be freed by 293.Xr free 3 . 294.Pp 295The 296.Fn getaddrinfo_async 297function is an asynchronous version of the 298.Xr getaddrinfo 3 299call. 300It provides a chain of addrinfo structures with all valid combinations of 301socket address for the given 302.Fa hostname , 303.Fa servname 304and 305.Fa hints . 306Those three parameters have the same meaning as for the blocking counterpart. 307Upon completion the return code is set in 308.Fa ar_gai_errno . 309The 310.Fa ar_errno 311member may also be set. 312On success, the 313.Fa ar_addrinfo 314member points to a newly allocated list of addrinfo. 315This list must be freed with 316.Xr freeaddrinfo 3 . 317.Sh WORKING WITH THREADS 318This implementation of the asynchronous resolver interface is thread-safe 319and lock-free internally, but the following restriction applies: 320Two different threads must not create queries on the same context or 321run queries originating from the same context at the same time. 322If they want to do that, all calls must be protected by a mutex around 323that context. 324.Pp 325It is generally not a problem since the main point of the asynchronous 326resolver is to multiplex queries within a single thread of control, 327so sharing a resolver among threads is not useful. 328.Sh SEE ALSO 329.Xr getaddrinfo 3 , 330.Xr gethostbyname 3 , 331.Xr getnameinfo 3 , 332.Xr getnetbyname 3 , 333.Xr getrrsetbyname 3 , 334.Xr res_send 3 , 335.Xr resolv.conf 5 336