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.
This commit is contained in:
parent
59b4f7f45e
commit
33dee81933
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=126243
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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.
|
||||
|
@ -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,10 +2152,13 @@ _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);
|
||||
__ypcurrent = NULL;
|
||||
@ -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.
|
||||
|
@ -116,7 +116,6 @@ typedef union {
|
||||
char ac;
|
||||
} align;
|
||||
|
||||
extern int h_errno;
|
||||
int _dns_ttl_;
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -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
|
||||
|
@ -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];
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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,17 +1932,16 @@ _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;
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,14 @@ __FBSDID("$FreeBSD$");
|
||||
#include <unistd.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#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 <resolv.h>.
|
||||
|
@ -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;
|
||||
|
||||
|
82
lib/libc/net/res_send_private.h
Normal file
82
lib/libc/net/res_send_private.h
Normal file
@ -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);
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user