From 33dee819339974eaf7dbf69068001771cbdcd548 Mon Sep 17 00:00:00 2001 From: Brian Feldman Date: Wed, 25 Feb 2004 21:03:46 +0000 Subject: [PATCH] Make the resolver(3) and many associated interfaces much more reentrant. The getaddrinfo(3), getipnodebyname(3) and resolver(3) can coincide now with what should be totally reentrant, and h_errno values will now be preserved correctly, but this does not affect interfaces such as gethostbyname(3) which are still mostly non-reentrant. In all of these relevant functions, the thread-safety has been pushed down as far as it seems possible right now. This means that operations that are selected via nsdispatch(3) (i.e. files, yp, dns) are protected still under global locks that getaddrinfo(3) defines, but where possible the locking is greatly reduced. The most noticeable improvement is that multiple DNS lookups can now be run at the same time, and this shows major improvement in performance of DNS-lookup threaded programs, and solves the "Mozilla tab serialization" problem. No single-threaded applications need to be recompiled. Multi-threaded applications that reference "_res" to change resolver(3) options will need to be recompiled, and ones which reference "h_errno" will also if they desire the correct h_errno values. If the applications already understood that _res and h_errno were not thread-safe and had their own locking, they will see no performance improvement but will not actually break in any way. Please note that when NSS modules are used, or when nsdispatch(3) defaults to adding any lookups of its own to the individual libc _nsdispatch() calls, those MUST be reentrant as well. --- include/netdb.h | 5 +- include/resolv.h | 7 +- lib/libc/include/reentrant.h | 3 + lib/libc/net/getaddrinfo.3 | 8 +- lib/libc/net/getaddrinfo.c | 27 ++++--- lib/libc/net/gethostbydns.c | 1 - lib/libc/net/gethostbyname.3 | 6 ++ lib/libc/net/gethostbynis.c | 2 - lib/libc/net/getipnodebyname.3 | 11 ++- lib/libc/net/herror.c | 7 +- lib/libc/net/name6.c | 27 +++---- lib/libc/net/res_init.c | 128 +++++++++++++++++++++++++++++--- lib/libc/net/res_send.c | 19 +++-- lib/libc/net/res_send_private.h | 82 ++++++++++++++++++++ lib/libc/net/resolver.3 | 11 +++ 15 files changed, 289 insertions(+), 55 deletions(-) create mode 100644 lib/libc/net/res_send_private.h diff --git a/include/netdb.h b/include/netdb.h index 0fa4d16c57f8..ba3ed32f39a9 100644 --- a/include/netdb.h +++ b/include/netdb.h @@ -82,7 +82,7 @@ typedef __socklen_t socklen_t; #define _PATH_PROTOCOLS "/etc/protocols" #define _PATH_SERVICES "/etc/services" -extern int h_errno; +#define h_errno (*__h_error()) /* * Structures returned by network data base library. All addresses are @@ -135,7 +135,7 @@ struct addrinfo { /* * Error return codes from gethostbyname() and gethostbyaddr() - * (left in extern int h_errno). + * (left in h_errno). */ #define NETDB_INTERNAL -1 /* see errno */ @@ -254,6 +254,7 @@ void setservent(int); */ /* DO NOT USE THESE, THEY ARE SUBJECT TO CHANGE AND ARE NOT PORTABLE!!! */ +int * __h_error(void); void _sethosthtent(int); void _endhosthtent(void); void _sethostdnsent(int); diff --git a/include/resolv.h b/include/resolv.h index 9305023dbb9a..942d2d6f8721 100644 --- a/include/resolv.h +++ b/include/resolv.h @@ -200,7 +200,12 @@ struct res_sym { char * humanname; /* Its fun name, like "mail exchanger" */ }; -extern struct __res_state _res; +__BEGIN_DECLS +extern struct __res_state *___res(void); +extern struct __res_state_ext *___res_ext(void); +__END_DECLS +#define _res (*___res()) +#define _res_ext (*___res_ext()) /* for INET6 */ extern struct __res_state_ext _res_ext; diff --git a/lib/libc/include/reentrant.h b/lib/libc/include/reentrant.h index 8ce3af67e304..8ab328bc6279 100644 --- a/lib/libc/include/reentrant.h +++ b/lib/libc/include/reentrant.h @@ -94,10 +94,12 @@ #define mutex_t pthread_mutex_t #define cond_t pthread_cond_t #define rwlock_t pthread_rwlock_t +#define once_t pthread_once_t #define thread_key_t pthread_key_t #define MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER #define RWLOCK_INITIALIZER PTHREAD_RWLOCK_INITIALIZER +#define ONCE_INITIALIZER PTHREAD_ONCE_INIT #define mutex_init(m, a) _pthread_mutex_init(m, a) #define mutex_lock(m) if (__isthreaded) \ @@ -127,6 +129,7 @@ #define thr_getspecific(k) _pthread_getspecific(k) #define thr_sigsetmask(f, n, o) _pthread_sigmask(f, n, o) +#define thr_once(o, i) _pthread_once(o, i) #define thr_self() _pthread_self() #define thr_exit(x) _pthread_exit(x) #define thr_main() _pthread_main_np() diff --git a/lib/libc/net/getaddrinfo.3 b/lib/libc/net/getaddrinfo.3 index 36922dab8521..472a9183ac18 100644 --- a/lib/libc/net/getaddrinfo.3 +++ b/lib/libc/net/getaddrinfo.3 @@ -618,10 +618,14 @@ and documented in (RFC2553). .\" .Sh BUGS -Though the current implementation should be thread-safe, using +Although the current implementation is otherwise thread-safe, using .Fn getaddrinfo in conjunction with .Fn gethostby* -breaks thread-safeness. +(see +.Xr gethostbyname 3 ) +or +.Xr yp 8 +breaks the thread-safety of both. .Pp The text was shamelessly copied from RFC2553. diff --git a/lib/libc/net/getaddrinfo.c b/lib/libc/net/getaddrinfo.c index df05b0e53847..dc21cc231f04 100644 --- a/lib/libc/net/getaddrinfo.c +++ b/lib/libc/net/getaddrinfo.c @@ -305,10 +305,10 @@ static struct ai_errlist { }; /* - * XXX: Our res_*() is not thread-safe. So, we share lock between + * XXX: Many dependencies are not thread-safe. So, we share lock between * getaddrinfo() and getipnodeby*(). Still, we cannot use * getaddrinfo() and getipnodeby*() in conjunction with other - * functions which call res_*(). + * functions which call them. */ pthread_mutex_t __getaddrinfo_thread_lock = PTHREAD_MUTEX_INITIALIZER; #define THREAD_LOCK() \ @@ -1348,9 +1348,13 @@ get_port(ai, servname, matchonly) break; } - if ((sp = getservbyname(servname, proto)) == NULL) + THREAD_LOCK(); + if ((sp = getservbyname(servname, proto)) == NULL) { + THREAD_UNLOCK(); return EAI_SERVICE; + } port = sp->s_port; + THREAD_UNLOCK(); } if (!matchonly) { @@ -1501,15 +1505,11 @@ explore_fqdn(pai, hostname, servname, res) result = NULL; - THREAD_LOCK(); - /* * if the servname does not match socktype/protocol, ignore it. */ - if (get_portmatch(pai, servname) != 0) { - THREAD_UNLOCK(); + if (get_portmatch(pai, servname) != 0) return 0; - } switch (_nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo", default_dns_files, hostname, pai)) { @@ -1530,14 +1530,12 @@ explore_fqdn(pai, hostname, servname, res) } break; } - THREAD_UNLOCK(); *res = result; return 0; free: - THREAD_UNLOCK(); if (result) freeaddrinfo(result); return error; @@ -2037,6 +2035,7 @@ _files_getaddrinfo(rv, cb_data, ap) memset(&sentinel, 0, sizeof(sentinel)); cur = &sentinel; + THREAD_LOCK(); _sethtent(); while ((p = _gethtent(name, pai)) != NULL) { cur->ai_next = p; @@ -2044,6 +2043,7 @@ _files_getaddrinfo(rv, cb_data, ap) cur = cur->ai_next; } _endhtent(); + THREAD_UNLOCK(); *((struct addrinfo **)rv) = sentinel.ai_next; if (sentinel.ai_next == NULL) @@ -2152,9 +2152,12 @@ _yp_getaddrinfo(rv, cb_data, ap) memset(&sentinel, 0, sizeof(sentinel)); cur = &sentinel; + THREAD_LOCK(); if (!__ypdomain) { - if (_yp_check(&__ypdomain) == 0) + if (_yp_check(&__ypdomain) == 0) { + THREAD_UNLOCK(); return NS_UNAVAIL; + } } if (__ypcurrent) free(__ypcurrent); @@ -2189,6 +2192,7 @@ _yp_getaddrinfo(rv, cb_data, ap) cur = cur->ai_next; } } + THREAD_UNLOCK(); if (sentinel.ai_next == NULL) { h_errno = HOST_NOT_FOUND; @@ -2202,7 +2206,6 @@ _yp_getaddrinfo(rv, cb_data, ap) /* resolver logic */ extern const char *__hostalias(const char *); -extern int h_errno; /* * Formulate a normal query, send, and await answer. diff --git a/lib/libc/net/gethostbydns.c b/lib/libc/net/gethostbydns.c index 02cd223b2439..82f515214caf 100644 --- a/lib/libc/net/gethostbydns.c +++ b/lib/libc/net/gethostbydns.c @@ -116,7 +116,6 @@ typedef union { char ac; } align; -extern int h_errno; int _dns_ttl_; #ifdef DEBUG diff --git a/lib/libc/net/gethostbyname.3 b/lib/libc/net/gethostbyname.3 index e703e3221275..a4486bc6e9f8 100644 --- a/lib/libc/net/gethostbyname.3 +++ b/lib/libc/net/gethostbyname.3 @@ -369,6 +369,12 @@ version 4.9.4. These functions use static data storage; if the data is needed for future use, it should be copied before any subsequent calls overwrite it. +Threaded applications should never use them, as they will also conflict +with the +.Xr getaddrinfo 3 +and +.Xr getipnodebyname 3 +families of functions (which should be used instead). Only the Internet address format is currently understood. .Pp diff --git a/lib/libc/net/gethostbynis.c b/lib/libc/net/gethostbynis.c index 73b12edbc15b..88bd310b8dca 100644 --- a/lib/libc/net/gethostbynis.c +++ b/lib/libc/net/gethostbynis.c @@ -48,8 +48,6 @@ __FBSDID("$FreeBSD$"); #define MAXALIASES 35 #define MAXADDRS 35 -extern int h_errno; - #ifdef YP static char *host_aliases[MAXALIASES]; static char hostaddr[MAXADDRS]; diff --git a/lib/libc/net/getipnodebyname.3 b/lib/libc/net/getipnodebyname.3 index d0b0b8cffefe..1ade42d2cee8 100644 --- a/lib/libc/net/getipnodebyname.3 +++ b/lib/libc/net/getipnodebyname.3 @@ -455,6 +455,15 @@ are documented in (RFC2553). .\" .Sh BUGS +Although the current implementation is otherwise thread-safe, using +it in conjunction with +.Fn gethostby* +(see +.Xr gethostbyname 3 ) +or +.Xr yp 8 +breaks the thread-safety of both. +.Pp The .Fn getipnodebyname and @@ -469,6 +478,4 @@ and .Fn getnameinfo 3 are recommended. .Pp -The current implementation is not thread-safe. -.Pp The text was shamelessly copied from RFC2553. diff --git a/lib/libc/net/herror.c b/lib/libc/net/herror.c index 9f3dbb7d18f2..b84c06c1069f 100644 --- a/lib/libc/net/herror.c +++ b/lib/libc/net/herror.c @@ -69,9 +69,7 @@ const char *h_errlist[] = { "Unknown server error", /* 3 NO_RECOVERY */ "No address associated with name", /* 4 NO_ADDRESS */ }; -int h_nerr = { sizeof h_errlist / sizeof h_errlist[0] }; - -int h_errno; +const int h_nerr = { sizeof h_errlist / sizeof h_errlist[0] }; /* * herror -- @@ -110,3 +108,6 @@ hstrerror(err) return (h_errlist[err]); return ("Unknown resolver error"); } + +#undef h_errno +int h_errno; diff --git a/lib/libc/net/name6.c b/lib/libc/net/name6.c index c8abf9a4d76c..3d42e3c196bc 100644 --- a/lib/libc/net/name6.c +++ b/lib/libc/net/name6.c @@ -211,10 +211,10 @@ static int _icmp_ghbyaddr(void *, void *, va_list); #endif /* ICMPNL */ /* - * XXX: Our res_*() is not thread-safe. So, we share lock between + * XXX: Many dependencies are not thread-safe. So, we share lock between * getaddrinfo() and getipnodeby*(). Still, we cannot use * getaddrinfo() and getipnodeby*() in conjunction with other - * functions which call res_*(). + * functions which call them. */ #include "libc_private.h" extern pthread_mutex_t __getaddrinfo_thread_lock; @@ -309,10 +309,8 @@ _ghbyname(const char *name, int af, int flags, int *errp) } } - THREAD_LOCK(); rval = _nsdispatch(&hp, dtab, NSDB_HOSTS, "ghbyname", default_src, name, af, errp); - THREAD_UNLOCK(); return (rval == NS_SUCCESS) ? hp : NULL; } @@ -456,10 +454,8 @@ getipnodebyaddr(const void *src, size_t len, int af, int *errp) return NULL; } - THREAD_LOCK(); rval = _nsdispatch(&hp, dtab, NSDB_HOSTS, "ghbyaddr", default_src, src, len, af, errp); - THREAD_UNLOCK(); return (rval == NS_SUCCESS) ? hp : NULL; } @@ -1169,9 +1165,11 @@ _nis_ghbyname(void *rval, void *cb_data, va_list ap) if (af == AF_UNSPEC) af = AF_INET; if (af == AF_INET) { + THREAD_LOCK(); hp = _gethostbynisname(name, af); if (hp != NULL) hp = _hpcopy(hp, errp); + THREAD_UNLOCK(); } *(struct hostent **)rval = hp; @@ -1193,9 +1191,11 @@ _nis_ghbyaddr(void *rval, void *cb_data, va_list ap) af = va_arg(ap, int); if (af == AF_INET) { + THREAD_LOCK(); hp = _gethostbynisaddr(addr, addrlen, af); if (hp != NULL) hp = _hpcopy(hp, errp); + THREAD_UNLOCK(); } *(struct hostent **)rval = hp; return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND; @@ -1932,18 +1932,17 @@ _icmp_fqdn_query(const struct in6_addr *addr, int ifindex) struct timeval tout; int len; char *name; - static int pid; static struct _icmp_host_cache *hc_head; + THREAD_LOCK(); for (hc = hc_head; hc; hc = hc->hc_next) { if (hc->hc_ifindex == ifindex - && IN6_ARE_ADDR_EQUAL(&hc->hc_addr, addr)) - return hc->hc_name; + && IN6_ARE_ADDR_EQUAL(&hc->hc_addr, addr)) { + THREAD_UNLOCK(); + return hc->hc_name; /* XXX: never freed */ + } } - if (pid == 0) - pid = getpid(); - ICMP6_FILTER_SETBLOCKALL(&filter); ICMP6_FILTER_SETPASS(ICMP6_FQDN_REPLY, &filter); @@ -1955,7 +1954,7 @@ _icmp_fqdn_query(const struct in6_addr *addr, int ifindex) fq->icmp6_fqdn_type = ICMP6_FQDN_QUERY; fq->icmp6_fqdn_code = 0; fq->icmp6_fqdn_cksum = 0; - fq->icmp6_fqdn_id = (u_short)pid; + fq->icmp6_fqdn_id = (u_short)getpid(); fq->icmp6_fqdn_unused = 0; fq->icmp6_fqdn_cookie[0] = 0; fq->icmp6_fqdn_cookie[1] = 0; @@ -2038,8 +2037,10 @@ _icmp_fqdn_query(const struct in6_addr *addr, int ifindex) hc->hc_ifindex = ifindex; hc->hc_addr = *addr; hc->hc_name = strdup(name); + THREAD_LOCK(); hc->hc_next = hc_head; hc_head = hc; + THREAD_UNLOCK(); return hc->hc_name; } diff --git a/lib/libc/net/res_init.c b/lib/libc/net/res_init.c index 6c229730df77..1d48f606d156 100644 --- a/lib/libc/net/res_init.c +++ b/lib/libc/net/res_init.c @@ -91,7 +91,14 @@ __FBSDID("$FreeBSD$"); #include #include +#include "namespace.h" +#include "reentrant.h" +#include "un-namespace.h" #include "res_config.h" +#include "res_send_private.h" + +#undef h_errno +extern int h_errno; static void res_setoptions(char *, char *); @@ -106,16 +113,14 @@ static u_int32_t net_mask(struct in_addr); #endif /* - * Resolver state default settings. + * Check structure for failed per-thread allocations. */ - -struct __res_state _res -# if defined(__BIND_RES_TEXT) - = { RES_TIMEOUT, } /* Motorola, et al. */ -# endif - ; - -struct __res_state_ext _res_ext; +static struct res_per_thread { + struct __res_state res_state; + struct __res_state_ext res_state_ext; + struct __res_send_private res_send_private; + int h_errno; +} _res_per_thread_bogus = { .res_send_private = { .s = -1 } }; /* socket */ /* * Set up default settings. If the configuration file exist, the values @@ -142,6 +147,7 @@ int res_init() { FILE *fp; + struct __res_send_private *rsp; char *cp, **pp; int n; char buf[MAXDNAME]; @@ -156,6 +162,19 @@ res_init() int dots; #endif + /* + * If allocation of memory for this thread's resolver has failed, + * return the error to the user. + */ + if (&_res == &_res_per_thread_bogus.res_state) + return (-1); + rsp = ___res_send_private(); + rsp->s = -1; + rsp->connected = 0; + rsp->vc = 0; + rsp->af = 0; + rsp->Qhook = NULL; + rsp->Rhook = NULL; /* * These three fields used to be statically initialized. This made * it hard to use this code in a shared library. It is necessary, @@ -597,6 +616,97 @@ res_randomid() return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid())); } +/* + * Resolver state default settings. + */ + +#undef _res +#undef _res_ext +#ifdef __BIND_RES_TEXT +struct __res_state _res = { RES_TIMEOUT }; /* Motorola, et al. */ +#else +struct __res_state _res; +#endif +struct __res_state_ext _res_ext; +static struct __res_send_private _res_send_private = { .s = -1 }; /* socket */ + +static thread_key_t res_key; +static once_t res_init_once = ONCE_INITIALIZER; +static int res_thr_keycreated = 0; + +static void +free_res(void *ptr) +{ + struct res_per_thread *myrsp = ptr; + + if (myrsp->res_state.options & RES_INIT) + res_close(); + free(myrsp); +} + +static void +res_keycreate(void) +{ + res_thr_keycreated = thr_keycreate(&res_key, free_res) == 0; +} + +static struct res_per_thread * +allocate_res(void) +{ + struct res_per_thread *myrsp; + + if (thr_once(&res_init_once, res_keycreate) != 0 || + !res_thr_keycreated) + return (&_res_per_thread_bogus); + + myrsp = thr_getspecific(res_key); + if (myrsp != NULL) + return (myrsp); + myrsp = calloc(1, sizeof(*myrsp)); + if (myrsp == NULL) + return (&_res_per_thread_bogus); +#ifdef __BIND_RES_TEXT + myrsp->res_state.options = RES_TIMEOUT; /* Motorola, et al. */ +#endif + myrsp->res_send_private.s = -1; /* socket */ + if (thr_setspecific(res_key, myrsp) == 0) + return (myrsp); + free(myrsp); + return (&_res_per_thread_bogus); +} + +struct __res_state * +___res(void) +{ + if (thr_main() != 0) + return (&_res); + return (&allocate_res()->res_state); +} + +struct __res_state_ext * +___res_ext(void) +{ + if (thr_main() != 0) + return (&_res_ext); + return (&allocate_res()->res_state_ext); +} + +struct __res_send_private * +___res_send_private(void) +{ + if (thr_main() != 0) + return (&_res_send_private); + return (&allocate_res()->res_send_private); +} + +int * +__h_error(void) +{ + if (thr_main() != 0) + return (&h_errno); + return (&allocate_res()->h_errno); +} + /* * Weak aliases for applications that use certain private entry points, * and fail to include . diff --git a/lib/libc/net/res_send.c b/lib/libc/net/res_send.c index fea5f5423d45..d39bbc5a09fa 100644 --- a/lib/libc/net/res_send.c +++ b/lib/libc/net/res_send.c @@ -101,14 +101,15 @@ __FBSDID("$FreeBSD$"); #include "un-namespace.h" #include "res_config.h" +#include "res_send_private.h" -static int s = -1; /* socket used for communications */ -static int connected = 0; /* is the socket connected */ -static int vc = 0; /* is the socket a virtual circuit? */ -static int af = 0; /* address family of socket */ -static res_send_qhook Qhook = NULL; -static res_send_rhook Rhook = NULL; +#define s ___res_send_private()->s +#define connected ___res_send_private()->connected +#define vc ___res_send_private()->vc +#define af ___res_send_private()->af +#define Qhook ___res_send_private()->Qhook +#define Rhook ___res_send_private()->Rhook #define CAN_RECONNECT 1 @@ -123,8 +124,6 @@ static res_send_rhook Rhook = NULL; fprintf args;\ __fp_nquery(query, size, stdout);\ } else {} -static char abuf[NI_MAXHOST]; -static char pbuf[NI_MAXSERV]; static void Aerror(FILE *, char *, int, struct sockaddr *); static void Perror(FILE *, char *, int); @@ -138,6 +137,9 @@ static void Perror(FILE *, char *, int); int save = errno; if (_res.options & RES_DEBUG) { + char abuf[NI_MAXHOST]; + char pbuf[NI_MAXSERV]; + if (getnameinfo(address, address->sa_len, abuf, sizeof(abuf), pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV|NI_WITHSCOPEID) != 0) { @@ -388,6 +390,7 @@ res_send(buf, buflen, ans, anssiz) */ for (try = 0; try < _res.retry; try++) { for (ns = 0; ns < _res.nscount; ns++) { + char abuf[NI_MAXHOST]; struct sockaddr *nsap = get_nsaddr(ns); socklen_t salen; diff --git a/lib/libc/net/res_send_private.h b/lib/libc/net/res_send_private.h new file mode 100644 index 000000000000..df96dda27608 --- /dev/null +++ b/lib/libc/net/res_send_private.h @@ -0,0 +1,82 @@ +/* $FreeBSD$ */ + +/* + * Copyright (c) 1985, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +struct __res_send_private { + int s; /* socket used for communications */ + int connected; /* is the socket connected */ + int vc; /* is the socket a virtual circuit? */ + int af; /* address family of socket */ + res_send_qhook Qhook; + res_send_rhook Rhook; +}; + +struct __res_send_private *___res_send_private(void); diff --git a/lib/libc/net/resolver.3 b/lib/libc/net/resolver.3 index 7c5e7bb61d32..68d80d8eeb8a 100644 --- a/lib/libc/net/resolver.3 +++ b/lib/libc/net/resolver.3 @@ -396,6 +396,17 @@ function puts a 32-bit quantity .Fa src to a buffer pointed to by .Fa dst . +.Sh RETURN VALUES +The +.Fn res_init +function will return 0 on success, or -1 in a threaded program if +per-thread storage could not be allocated. +.Sh IMPLEMENTATION NOTES +This implementation of the resolver is thread-safe, but it will not +function properly if the programmer attempts to declare his or her own +.Va _res +structure in an attempt to replace the per-thread version referred to +by that macro. .Sh FILES .Bl -tag -width /etc/resolv.conf .It Pa /etc/resolv.conf