Merge "Fix nan output in the printf family."
diff --git a/benchmarks/pthread_benchmark.cpp b/benchmarks/pthread_benchmark.cpp
index 92e5998..42023e0 100644
--- a/benchmarks/pthread_benchmark.cpp
+++ b/benchmarks/pthread_benchmark.cpp
@@ -47,6 +47,21 @@
}
BENCHMARK(BM_pthread_getspecific);
+static void BM_pthread_setspecific(int iters) {
+ StopBenchmarkTiming();
+ pthread_key_t key;
+ pthread_key_create(&key, NULL);
+ StartBenchmarkTiming();
+
+ for (int i = 0; i < iters; ++i) {
+ pthread_setspecific(key, NULL);
+ }
+
+ StopBenchmarkTiming();
+ pthread_key_delete(key);
+}
+BENCHMARK(BM_pthread_setspecific);
+
static void DummyPthreadOnceInitFunction() {
}
@@ -137,3 +152,80 @@
pthread_rwlock_destroy(&lock);
}
BENCHMARK(BM_pthread_rw_lock_write);
+
+static void* IdleThread(void*) {
+ return NULL;
+}
+
+static void BM_pthread_create(int iters) {
+ StopBenchmarkTiming();
+ pthread_t thread;
+
+ for (int i = 0; i < iters; ++i) {
+ StartBenchmarkTiming();
+ pthread_create(&thread, NULL, IdleThread, NULL);
+ StopBenchmarkTiming();
+ pthread_join(thread, NULL);
+ }
+}
+BENCHMARK(BM_pthread_create);
+
+static void* RunThread(void*) {
+ StopBenchmarkTiming();
+ return NULL;
+}
+
+static void BM_pthread_create_and_run(int iters) {
+ StopBenchmarkTiming();
+ pthread_t thread;
+
+ for (int i = 0; i < iters; ++i) {
+ StartBenchmarkTiming();
+ pthread_create(&thread, NULL, RunThread, NULL);
+ pthread_join(thread, NULL);
+ }
+}
+BENCHMARK(BM_pthread_create_and_run);
+
+static void* ExitThread(void*) {
+ StartBenchmarkTiming();
+ pthread_exit(NULL);
+}
+
+static void BM_pthread_exit_and_join(int iters) {
+ StopBenchmarkTiming();
+ pthread_t thread;
+
+ for (int i = 0; i < iters; ++i) {
+ pthread_create(&thread, NULL, ExitThread, NULL);
+ pthread_join(thread, NULL);
+ StopBenchmarkTiming();
+ }
+}
+BENCHMARK(BM_pthread_exit_and_join);
+
+static void BM_pthread_key_create(int iters) {
+ StopBenchmarkTiming();
+ pthread_key_t key;
+
+ for (int i = 0; i < iters; ++i) {
+ StartBenchmarkTiming();
+ pthread_key_create(&key, NULL);
+ StopBenchmarkTiming();
+ pthread_key_delete(key);
+ }
+}
+BENCHMARK(BM_pthread_key_create);
+
+static void BM_pthread_key_delete(int iters) {
+ StopBenchmarkTiming();
+ pthread_key_t key;
+
+ for (int i = 0; i < iters; ++i) {
+ pthread_key_create(&key, NULL);
+ StartBenchmarkTiming();
+ pthread_key_delete(key);
+ StopBenchmarkTiming();
+ }
+}
+BENCHMARK(BM_pthread_key_delete);
diff --git a/libc/NOTICE b/libc/NOTICE
index 697b8fc..1fa31c2 100644
--- a/libc/NOTICE
+++ b/libc/NOTICE
@@ -1679,35 +1679,6 @@
-------------------------------------------------------------------
-Copyright (c) 1990 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. 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.
-
--------------------------------------------------------------------
-
Copyright (c) 1990 The Regents of the University of California.
All rights reserved.
@@ -2539,33 +2510,6 @@
-------------------------------------------------------------------
-Copyright (c) 1993 Christopher G. Demetriou
-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. The name of the author may not be used to endorse or promote products
- derived from this software without specific prior written permission
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
-
--------------------------------------------------------------------
-
Copyright (c) 1993 Martin Birgmeier
All rights reserved.
@@ -2685,63 +2629,6 @@
-------------------------------------------------------------------
-Copyright (c) 1996-2004 Per Fogelstrom, Opsycon AB
-
-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.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
-
--------------------------------------------------------------------
-
-Copyright (c) 1997 Mark Brinicombe
-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 Mark Brinicombe
-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 AUTHOR 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 AUTHOR 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.
-
--------------------------------------------------------------------
-
Copyright (c) 1997 Mark Brinicombe
Copyright (c) 2010 Android Open Source Project.
All rights reserved.
@@ -3365,34 +3252,6 @@
-------------------------------------------------------------------
-Copyright (c) 2002 Opsycon AB (www.opsycon.se / www.opsycon.com)
-
-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. Neither the name of Opsycon AB 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 AUTHOR ``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 AUTHOR 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.
-
--------------------------------------------------------------------
-
Copyright (c) 2002 The NetBSD Foundation, Inc.
All rights reserved.
@@ -4025,6 +3884,22 @@
-------------------------------------------------------------------
+Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
+
+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 THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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.
+
+-------------------------------------------------------------------
+
Copyright (c) 2008 Todd C. Miller <millert@openbsd.org>
Permission to use, copy, modify, and distribute this software for any
@@ -4611,35 +4486,32 @@
-------------------------------------------------------------------
-Copyright (c) 2013, Linaro Limited
- All rights reserved.
+Copyright (c) 2013 The NetBSD Foundation, Inc.
+All rights reserved.
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
+This code is derived from software contributed to The NetBSD Foundation
+by Christos Zoulas.
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+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.
- * 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.
-
- * Neither the name of Linaro Limited 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 COPYRIGHT HOLDERS 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 COPYRIGHT
- HOLDER 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.
+THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
-------------------------------------------------------------------
diff --git a/libc/arch-mips/include/machine/elf_machdep.h b/libc/arch-mips/include/machine/elf_machdep.h
index d27d431..0aacedf 100644
--- a/libc/arch-mips/include/machine/elf_machdep.h
+++ b/libc/arch-mips/include/machine/elf_machdep.h
@@ -121,6 +121,7 @@
#define DT_MIPS_GOTSYM 0x70000013 /* first dynamic sym in got */
#define DT_MIPS_HIPAGENO 0x70000014
#define DT_MIPS_RLD_MAP 0x70000016 /* address of loader map */
+#define DT_MIPS_RLD_MAP2 0x70000035 /* offset of loader map, used for PIE */
/*
* ELF Flags
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index 2a6a03b..15b3fd5 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -74,9 +74,7 @@
void __libc_init_tls(KernelArgumentBlock& args) {
__libc_auxv = args.auxv;
- static void* tls[BIONIC_TLS_SLOTS];
static pthread_internal_t main_thread;
- main_thread.tls = tls;
// Tell the kernel to clear our tid field when we exit, so we're like any other pthread.
// As a side-effect, this tells us our pid (which is the same as the main thread's tid).
@@ -96,7 +94,7 @@
__init_thread(&main_thread, false);
__init_tls(&main_thread);
__set_tls(main_thread.tls);
- tls[TLS_SLOT_BIONIC_PREINIT] = &args;
+ main_thread.tls[TLS_SLOT_BIONIC_PREINIT] = &args;
__init_alternate_signal_stack(&main_thread);
}
diff --git a/libc/bionic/pthread_create.cpp b/libc/bionic/pthread_create.cpp
index c99e69c..c47b750 100644
--- a/libc/bionic/pthread_create.cpp
+++ b/libc/bionic/pthread_create.cpp
@@ -35,6 +35,7 @@
#include "pthread_internal.h"
#include "private/bionic_macros.h"
+#include "private/bionic_prctl.h"
#include "private/bionic_ssp.h"
#include "private/bionic_tls.h"
#include "private/libc_logging.h"
@@ -72,6 +73,10 @@
ss.ss_flags = 0;
sigaltstack(&ss, NULL);
thread->alternate_signal_stack = ss.ss_sp;
+
+ // We can only use const static allocated string for mapped region name, as Android kernel
+ // uses the string pointer directly when dumping /proc/pid/maps.
+ prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ss.ss_sp, ss.ss_size, "thread signal stack");
}
}
@@ -101,31 +106,64 @@
return error;
}
-static void* __create_thread_stack(pthread_internal_t* thread) {
+static void* __create_thread_stack(const pthread_attr_t& attr) {
// Create a new private anonymous map.
int prot = PROT_READ | PROT_WRITE;
int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
- void* stack = mmap(NULL, thread->attr.stack_size, prot, flags, -1, 0);
+ void* stack = mmap(NULL, attr.stack_size, prot, flags, -1, 0);
if (stack == MAP_FAILED) {
__libc_format_log(ANDROID_LOG_WARN,
"libc",
"pthread_create failed: couldn't allocate %zd-byte stack: %s",
- thread->attr.stack_size, strerror(errno));
+ attr.stack_size, strerror(errno));
return NULL;
}
// Set the guard region at the end of the stack to PROT_NONE.
- if (mprotect(stack, thread->attr.guard_size, PROT_NONE) == -1) {
+ if (mprotect(stack, attr.guard_size, PROT_NONE) == -1) {
__libc_format_log(ANDROID_LOG_WARN, "libc",
"pthread_create failed: couldn't mprotect PROT_NONE %zd-byte stack guard region: %s",
- thread->attr.guard_size, strerror(errno));
- munmap(stack, thread->attr.stack_size);
+ attr.guard_size, strerror(errno));
+ munmap(stack, attr.stack_size);
return NULL;
}
return stack;
}
+static int __allocate_thread(pthread_attr_t* attr, pthread_internal_t** threadp, void** child_stack) {
+ if (attr->stack_base == NULL) {
+ // The caller didn't provide a stack, so allocate one.
+ // Make sure the stack size and guard size are multiples of PAGE_SIZE.
+ attr->stack_size = BIONIC_ALIGN(attr->stack_size, PAGE_SIZE);
+ attr->guard_size = BIONIC_ALIGN(attr->guard_size, PAGE_SIZE);
+ attr->stack_base = __create_thread_stack(*attr);
+ if (attr->stack_base == NULL) {
+ return EAGAIN;
+ }
+ } else {
+ // The caller did provide a stack, so remember we're not supposed to free it.
+ attr->flags |= PTHREAD_ATTR_FLAG_USER_ALLOCATED_STACK;
+ }
+
+ // Thread stack is used for two sections:
+ // pthread_internal_t.
+ // regular stack, from top to down.
+ uint8_t* stack_top = reinterpret_cast<uint8_t*>(attr->stack_base) + attr->stack_size;
+ stack_top -= sizeof(pthread_internal_t);
+ pthread_internal_t* thread = reinterpret_cast<pthread_internal_t*>(stack_top);
+
+ // No need to check stack_top alignment. The size of pthread_internal_t is 16-bytes aligned,
+ // and user allocated stack is guaranteed by pthread_attr_setstack.
+
+ thread->attr = *attr;
+ __init_tls(thread);
+
+ *threadp = thread;
+ *child_stack = stack_top;
+ return 0;
+}
+
static int __pthread_start(void* arg) {
pthread_internal_t* thread = reinterpret_cast<pthread_internal_t*>(arg);
@@ -158,43 +196,21 @@
// Inform the rest of the C library that at least one thread was created.
__isthreaded = 1;
- pthread_internal_t* thread = __create_thread_struct();
- if (thread == NULL) {
- return EAGAIN;
- }
-
+ pthread_attr_t thread_attr;
if (attr == NULL) {
- pthread_attr_init(&thread->attr);
+ pthread_attr_init(&thread_attr);
} else {
- thread->attr = *attr;
+ thread_attr = *attr;
attr = NULL; // Prevent misuse below.
}
- // Make sure the stack size and guard size are multiples of PAGE_SIZE.
- thread->attr.stack_size = BIONIC_ALIGN(thread->attr.stack_size, PAGE_SIZE);
- thread->attr.guard_size = BIONIC_ALIGN(thread->attr.guard_size, PAGE_SIZE);
-
- if (thread->attr.stack_base == NULL) {
- // The caller didn't provide a stack, so allocate one.
- thread->attr.stack_base = __create_thread_stack(thread);
- if (thread->attr.stack_base == NULL) {
- __free_thread_struct(thread);
- return EAGAIN;
- }
- } else {
- // The caller did provide a stack, so remember we're not supposed to free it.
- thread->attr.flags |= PTHREAD_ATTR_FLAG_USER_ALLOCATED_STACK;
+ pthread_internal_t* thread = NULL;
+ void* child_stack = NULL;
+ int result = __allocate_thread(&thread_attr, &thread, &child_stack);
+ if (result != 0) {
+ return result;
}
- // Make room for the TLS area.
- // The child stack is the same address, just growing in the opposite direction.
- // At offsets >= 0, we have the TLS slots.
- // At offsets < 0, we have the child stack.
- thread->tls = reinterpret_cast<void**>(reinterpret_cast<uint8_t*>(thread->attr.stack_base) +
- thread->attr.stack_size - BIONIC_ALIGN(BIONIC_TLS_SLOTS * sizeof(void*), 16));
- void* child_stack = thread->tls;
- __init_tls(thread);
-
// Create a mutex for the thread in TLS to wait on once it starts so we can keep
// it from doing anything until after we notify the debugger about it
//
@@ -211,7 +227,7 @@
int flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM |
CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID;
- void* tls = thread->tls;
+ void* tls = reinterpret_cast<void*>(thread->tls);
#if defined(__i386__)
// On x86 (but not x86-64), CLONE_SETTLS takes a pointer to a struct user_desc rather than
// a pointer to the TLS itself.
@@ -229,7 +245,6 @@
if (!thread->user_allocated_stack()) {
munmap(thread->attr.stack_base, thread->attr.stack_size);
}
- __free_thread_struct(thread);
__libc_format_log(ANDROID_LOG_WARN, "libc", "pthread_create failed: clone failed: %s", strerror(errno));
return clone_errno;
}
diff --git a/libc/bionic/pthread_detach.cpp b/libc/bionic/pthread_detach.cpp
index a8608e3..715acf1 100644
--- a/libc/bionic/pthread_detach.cpp
+++ b/libc/bionic/pthread_detach.cpp
@@ -46,7 +46,7 @@
if (thread->tid == 0) {
// Already exited; clean up.
- _pthread_internal_remove_locked(thread.get());
+ _pthread_internal_remove_locked(thread.get(), true);
return 0;
}
diff --git a/libc/bionic/pthread_exit.cpp b/libc/bionic/pthread_exit.cpp
index a6bb363..e04cf8e 100644
--- a/libc/bionic/pthread_exit.cpp
+++ b/libc/bionic/pthread_exit.cpp
@@ -90,7 +90,7 @@
// Keep track of what we need to know about the stack before we lose the pthread_internal_t.
void* stack_base = thread->attr.stack_base;
size_t stack_size = thread->attr.stack_size;
- bool user_allocated_stack = thread->user_allocated_stack();
+ bool free_stack = false;
pthread_mutex_lock(&g_thread_list_lock);
if ((thread->attr.flags & PTHREAD_ATTR_FLAG_DETACHED) != 0) {
@@ -98,24 +98,18 @@
// First make sure that the kernel does not try to clear the tid field
// because we'll have freed the memory before the thread actually exits.
__set_tid_address(NULL);
- _pthread_internal_remove_locked(thread);
- } else {
- // Make sure that the pthread_internal_t doesn't have stale pointers to a stack that
- // will be unmapped after the exit call below.
- if (!user_allocated_stack) {
- thread->attr.stack_base = NULL;
- thread->attr.stack_size = 0;
- thread->tls = NULL;
+
+ // pthread_internal_t is freed below with stack, not here.
+ _pthread_internal_remove_locked(thread, false);
+ if (!thread->user_allocated_stack()) {
+ free_stack = true;
}
- // pthread_join is responsible for destroying the pthread_internal_t for non-detached threads.
- // The kernel will futex_wake on the pthread_internal_t::tid field to wake pthread_join.
}
pthread_mutex_unlock(&g_thread_list_lock);
- if (user_allocated_stack) {
- // Cleaning up this thread's stack is the creator's responsibility, not ours.
- __exit(0);
- } else {
+ // Detached threads exit with stack teardown, and everything deallocated here.
+ // Threads that can be joined exit but leave their stacks for the pthread_join caller to clean up.
+ if (free_stack) {
// We need to munmap the stack we're running on before calling exit.
// That's not something we can do in C.
@@ -126,5 +120,7 @@
sigprocmask(SIG_SETMASK, &mask, NULL);
_exit_with_stack_teardown(stack_base, stack_size);
+ } else {
+ __exit(0);
}
}
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index c5136c9..95097b7 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -30,6 +30,8 @@
#include <pthread.h>
+#include "private/bionic_tls.h"
+
/* Has the thread been detached by a pthread_join or pthread_detach call? */
#define PTHREAD_ATTR_FLAG_DETACHED 0x00000001
@@ -72,8 +74,6 @@
return (attr.flags & PTHREAD_ATTR_FLAG_USER_ALLOCATED_STACK) != 0;
}
- void** tls;
-
pthread_attr_t attr;
__pthread_cleanup_t* cleanup_stack;
@@ -86,16 +86,16 @@
pthread_mutex_t startup_handshake_mutex;
+ void* tls[BIONIC_TLS_SLOTS];
+
/*
* The dynamic linker implements dlerror(3), which makes it hard for us to implement this
* per-thread buffer by simply using malloc(3) and free(3).
*/
#define __BIONIC_DLERROR_BUFFER_SIZE 512
char dlerror_buffer[__BIONIC_DLERROR_BUFFER_SIZE];
-};
+} __attribute__((aligned(16))); // Align it as thread stack top below it should be aligned.
-__LIBC_HIDDEN__ pthread_internal_t* __create_thread_struct();
-__LIBC_HIDDEN__ void __free_thread_struct(pthread_internal_t*);
__LIBC_HIDDEN__ int __init_thread(pthread_internal_t* thread, bool add_to_thread_list);
__LIBC_HIDDEN__ void __init_tls(pthread_internal_t* thread);
__LIBC_HIDDEN__ void __init_alternate_signal_stack(pthread_internal_t*);
@@ -105,7 +105,7 @@
extern "C" __LIBC64_HIDDEN__ pthread_internal_t* __get_thread(void);
__LIBC_HIDDEN__ void pthread_key_clean_all(void);
-__LIBC_HIDDEN__ void _pthread_internal_remove_locked(pthread_internal_t* thread);
+__LIBC_HIDDEN__ void _pthread_internal_remove_locked(pthread_internal_t* thread, bool free_thread);
/*
* Traditionally we gave threads a 1MiB stack. When we started
diff --git a/libc/bionic/pthread_internals.cpp b/libc/bionic/pthread_internals.cpp
index 33cddd7..7c30e6e 100644
--- a/libc/bionic/pthread_internals.cpp
+++ b/libc/bionic/pthread_internals.cpp
@@ -41,26 +41,7 @@
pthread_internal_t* g_thread_list = NULL;
pthread_mutex_t g_thread_list_lock = PTHREAD_MUTEX_INITIALIZER;
-pthread_internal_t* __create_thread_struct() {
- void* result = mmap(NULL, sizeof(pthread_internal_t), PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
- if (result == MAP_FAILED) {
- __libc_format_log(ANDROID_LOG_WARN, "libc",
- "__create_thread_struct() failed: %s", strerror(errno));
- return NULL;
- }
- return reinterpret_cast<pthread_internal_t*>(result);
-}
-
-void __free_thread_struct(pthread_internal_t* thread) {
- int result = munmap(thread, sizeof(pthread_internal_t));
- if (result != 0) {
- __libc_format_log(ANDROID_LOG_WARN, "libc",
- "__free_thread_struct() failed: %s", strerror(errno));
- }
-}
-
-void _pthread_internal_remove_locked(pthread_internal_t* thread) {
+void _pthread_internal_remove_locked(pthread_internal_t* thread, bool free_thread) {
if (thread->next != NULL) {
thread->next->prev = thread->prev;
}
@@ -70,10 +51,11 @@
g_thread_list = thread->next;
}
- // The main thread is not heap-allocated. See __libc_init_tls for the declaration,
- // and __libc_init_common for the point where it's added to the thread list.
- if ((thread->attr.flags & PTHREAD_ATTR_FLAG_MAIN_THREAD) == 0) {
- __free_thread_struct(thread);
+ // For threads using user allocated stack (including the main thread), the pthread_internal_t
+ // can't be freed since it is on the stack.
+ if (free_thread && !(thread->attr.flags & PTHREAD_ATTR_FLAG_USER_ALLOCATED_STACK)) {
+ // Use one munmap to free the whole thread stack, including pthread_internal_t.
+ munmap(thread->attr.stack_base, thread->attr.stack_size);
}
}
diff --git a/libc/bionic/pthread_join.cpp b/libc/bionic/pthread_join.cpp
index 0cbed62..e3350ef 100644
--- a/libc/bionic/pthread_join.cpp
+++ b/libc/bionic/pthread_join.cpp
@@ -74,6 +74,6 @@
*return_value = thread->return_value;
}
- _pthread_internal_remove_locked(thread.get());
+ _pthread_internal_remove_locked(thread.get(), true);
return 0;
}
diff --git a/libc/bionic/pthread_key.cpp b/libc/bionic/pthread_key.cpp
index b47ef22..49b72e9 100644
--- a/libc/bionic/pthread_key.cpp
+++ b/libc/bionic/pthread_key.cpp
@@ -213,16 +213,6 @@
// Clear value in all threads.
pthread_mutex_lock(&g_thread_list_lock);
for (pthread_internal_t* t = g_thread_list; t != NULL; t = t->next) {
- // Skip zombie threads. They don't have a valid TLS area any more.
- // Similarly, it is possible to have t->tls == NULL for threads that
- // were just recently created through pthread_create() but whose
- // startup trampoline (__pthread_start) hasn't been run yet by the
- // scheduler. t->tls will also be NULL after a thread's stack has been
- // unmapped but before the ongoing pthread_join() is finished.
- if (t->tid == 0 || t->tls == NULL) {
- continue;
- }
-
t->tls[key] = NULL;
}
tls_map.DeleteKey(key);
diff --git a/libc/bionic/stubs.cpp b/libc/bionic/stubs.cpp
index 88e5ac5..ab67935 100644
--- a/libc/bionic/stubs.cpp
+++ b/libc/bionic/stubs.cpp
@@ -42,18 +42,44 @@
#include "private/libc_logging.h"
#include "private/ThreadLocalBuffer.h"
-GLOBAL_INIT_THREAD_LOCAL_BUFFER(stubs);
+// POSIX seems to envisage an implementation where the <pwd.h> functions are
+// implemented by brute-force searching with getpwent(3), and the <grp.h>
+// functions are implemented similarly with getgrent(3). This means that it's
+// okay for all the <grp.h> functions to share state, and all the <passwd.h>
+// functions to share state, but <grp.h> functions can't clobber <passwd.h>
+// functions' state and vice versa.
-struct stubs_state_t {
- passwd passwd_;
+GLOBAL_INIT_THREAD_LOCAL_BUFFER(group);
+
+struct group_state_t {
group group_;
char* group_members_[2];
- char app_name_buffer_[32];
char group_name_buffer_[32];
+};
+
+static group_state_t* __group_state() {
+ LOCAL_INIT_THREAD_LOCAL_BUFFER(group_state_t*, group, sizeof(group_state_t));
+ if (group_tls_buffer != NULL) {
+ memset(group_tls_buffer, 0, sizeof(group_state_t));
+ group_tls_buffer->group_.gr_mem = group_tls_buffer->group_members_;
+ }
+ return group_tls_buffer;
+}
+
+GLOBAL_INIT_THREAD_LOCAL_BUFFER(passwd);
+
+struct passwd_state_t {
+ passwd passwd_;
+ char app_name_buffer_[32];
char dir_buffer_[32];
char sh_buffer_[32];
};
+static passwd_state_t* __passwd_state() {
+ LOCAL_INIT_THREAD_LOCAL_BUFFER(passwd_state_t*, passwd, sizeof(passwd_state_t));
+ return passwd_tls_buffer;
+}
+
static int do_getpw_r(int by_name, const char* name, uid_t uid,
passwd* dst, char* buf, size_t byte_count,
passwd** result) {
@@ -91,7 +117,7 @@
// pw_passwd and pw_gecos are non-POSIX and unused (always NULL) in bionic.
dst->pw_passwd = NULL;
-#ifdef __LP64__
+#if defined(__LP64__)
dst->pw_gecos = NULL;
#endif
@@ -113,17 +139,7 @@
return do_getpw_r(0, NULL, uid, pwd, buf, byte_count, result);
}
-static stubs_state_t* __stubs_state() {
- LOCAL_INIT_THREAD_LOCAL_BUFFER(stubs_state_t*, stubs, sizeof(stubs_state_t));
-
- if (stubs_tls_buffer != NULL) {
- memset(stubs_tls_buffer, 0, sizeof(stubs_state_t));
- stubs_tls_buffer->group_.gr_mem = stubs_tls_buffer->group_members_;
- }
- return stubs_tls_buffer;
-}
-
-static passwd* android_iinfo_to_passwd(stubs_state_t* state,
+static passwd* android_iinfo_to_passwd(passwd_state_t* state,
const android_id_info* iinfo) {
snprintf(state->dir_buffer_, sizeof(state->dir_buffer_), "/");
snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/system/bin/sh");
@@ -145,7 +161,7 @@
return gr;
}
-static passwd* android_id_to_passwd(stubs_state_t* state, unsigned id) {
+static passwd* android_id_to_passwd(passwd_state_t* state, unsigned id) {
for (size_t n = 0; n < android_id_count; ++n) {
if (android_ids[n].aid == id) {
return android_iinfo_to_passwd(state, android_ids + n);
@@ -154,7 +170,7 @@
return NULL;
}
-static passwd* android_name_to_passwd(stubs_state_t* state, const char* name) {
+static passwd* android_name_to_passwd(passwd_state_t* state, const char* name) {
for (size_t n = 0; n < android_id_count; ++n) {
if (!strcmp(android_ids[n].name, name)) {
return android_iinfo_to_passwd(state, android_ids + n);
@@ -297,9 +313,7 @@
// AID_ISOLATED_START to AID_USER-1 -> u0_i1234
// AID_USER+ -> u1_radio, u1_a1234, u2_i1234, etc.
// returns a passwd structure (sets errno to ENOENT on failure).
-static passwd* app_id_to_passwd(uid_t uid, stubs_state_t* state) {
- passwd* pw = &state->passwd_;
-
+static passwd* app_id_to_passwd(uid_t uid, passwd_state_t* state) {
if (uid < AID_APP) {
errno = ENOENT;
return NULL;
@@ -316,18 +330,18 @@
snprintf(state->sh_buffer_, sizeof(state->sh_buffer_), "/system/bin/sh");
+ passwd* pw = &state->passwd_;
pw->pw_name = state->app_name_buffer_;
pw->pw_dir = state->dir_buffer_;
pw->pw_shell = state->sh_buffer_;
pw->pw_uid = uid;
pw->pw_gid = uid;
-
return pw;
}
// Translate a gid into the corresponding app_<gid>
// group structure (sets errno to ENOENT on failure).
-static group* app_id_to_group(gid_t gid, stubs_state_t* state) {
+static group* app_id_to_group(gid_t gid, group_state_t* state) {
if (gid < AID_APP) {
errno = ENOENT;
return NULL;
@@ -339,13 +353,11 @@
gr->gr_name = state->group_name_buffer_;
gr->gr_gid = gid;
gr->gr_mem[0] = gr->gr_name;
-
return gr;
}
-
passwd* getpwuid(uid_t uid) { // NOLINT: implementing bad function.
- stubs_state_t* state = __stubs_state();
+ passwd_state_t* state = __passwd_state();
if (state == NULL) {
return NULL;
}
@@ -358,7 +370,7 @@
}
passwd* getpwnam(const char* login) { // NOLINT: implementing bad function.
- stubs_state_t* state = __stubs_state();
+ passwd_state_t* state = __passwd_state();
if (state == NULL) {
return NULL;
}
@@ -372,12 +384,12 @@
// All users are in just one group, the one passed in.
int getgrouplist(const char* /*user*/, gid_t group, gid_t* groups, int* ngroups) {
- if (*ngroups < 1) {
- *ngroups = 1;
- return -1;
- }
- groups[0] = group;
- return (*ngroups = 1);
+ if (*ngroups < 1) {
+ *ngroups = 1;
+ return -1;
+ }
+ groups[0] = group;
+ return (*ngroups = 1);
}
char* getlogin() { // NOLINT: implementing bad function.
@@ -386,7 +398,7 @@
}
group* getgrgid(gid_t gid) { // NOLINT: implementing bad function.
- stubs_state_t* state = __stubs_state();
+ group_state_t* state = __group_state();
if (state == NULL) {
return NULL;
}
@@ -399,7 +411,7 @@
}
group* getgrnam(const char* name) { // NOLINT: implementing bad function.
- stubs_state_t* state = __stubs_state();
+ group_state_t* state = __group_state();
if (state == NULL) {
return NULL;
}
diff --git a/libc/dns/gethnamaddr.c b/libc/dns/gethnamaddr.c
deleted file mode 100644
index 736858f..0000000
--- a/libc/dns/gethnamaddr.c
+++ /dev/null
@@ -1,1405 +0,0 @@
-/* $NetBSD: gethnamaddr.c,v 1.70 2006/03/22 00:03:51 christos Exp $ */
-
-/*
- * ++Copyright++ 1985, 1988, 1993
- * -
- * Copyright (c) 1985, 1988, 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. 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.
- * -
- * --Copyright--
- */
-
-#include <sys/cdefs.h>
-#include <sys/types.h>
-
-#include <sys/param.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <arpa/nameser.h>
-#include "NetdClientDispatch.h"
-#include "resolv_netid.h"
-#include "resolv_private.h"
-#include "resolv_cache.h"
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <netdb.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <strings.h>
-#include <syslog.h>
-#include <unistd.h>
-
-#define ALIGNBYTES (sizeof(uintptr_t) - 1)
-#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)
-
-#ifndef LOG_AUTH
-# define LOG_AUTH 0
-#endif
-
-#define MULTI_PTRS_ARE_ALIASES 1 /* XXX - experimental */
-
-#include "nsswitch.h"
-#include <stdlib.h>
-#include <string.h>
-
-// This should be synchronized to ResponseCode.h
-static const int DnsProxyQueryResult = 222;
-
-static const char AskedForGot[] =
- "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
-
-#define MAXPACKET (64*1024)
-
-typedef union {
- HEADER hdr;
- u_char buf[MAXPACKET];
-} querybuf;
-
-typedef union {
- int32_t al;
- char ac;
-} align;
-
-#ifdef DEBUG
-static void dprintf(const char *, res_state, ...)
- __attribute__((__format__(__printf__, 1, 3)));
-#endif
-static struct hostent *getanswer(const querybuf *, int, const char *, int,
- res_state);
-static void map_v4v6_address(const char *, char *);
-static void map_v4v6_hostent(struct hostent *, char **, char *);
-static void addrsort(char **, int, res_state);
-
-static void _sethtent(int);
-static void _endhtent(void);
-static struct hostent *_gethtent(void);
-void ht_sethostent(int);
-void ht_endhostent(void);
-struct hostent *ht_gethostbyname(char *);
-struct hostent *ht_gethostbyaddr(const char *, int, int);
-void dns_service(void);
-#undef dn_skipname
-int dn_skipname(const u_char *, const u_char *);
-static int _gethtbyaddr(void *, void *, va_list);
-static int _gethtbyname(void *, void *, va_list);
-static struct hostent *_gethtbyname2(const char *, int);
-static int _dns_gethtbyaddr(void *, void *, va_list);
-static int _dns_gethtbyname(void *, void *, va_list);
-
-static struct hostent *gethostbyname_internal(const char *, int, res_state, unsigned, unsigned);
-
-static const ns_src default_dns_files[] = {
- { NSSRC_FILES, NS_SUCCESS },
- { NSSRC_DNS, NS_SUCCESS },
- { 0, 0 }
-};
-
-
-#ifdef DEBUG
-static void
-dprintf(const char *msg, res_state res, ...)
-{
- assert(msg != NULL);
-
- if (res->options & RES_DEBUG) {
- int save = errno;
- va_list ap;
-
- va_start (ap, res);
- vprintf(msg, ap);
- va_end (ap);
-
- errno = save;
- }
-}
-#else
-# define dprintf(msg, res, num) ((void)0) /*nada*/
-#endif
-
-#define BOUNDED_INCR(x) \
- do { \
- cp += (x); \
- if (cp > eom) { \
- h_errno = NO_RECOVERY; \
- return NULL; \
- } \
- } while (/*CONSTCOND*/0)
-
-#define BOUNDS_CHECK(ptr, count) \
- do { \
- if ((ptr) + (count) > eom) { \
- h_errno = NO_RECOVERY; \
- return NULL; \
- } \
- } while (/*CONSTCOND*/0)
-
-static struct hostent *
-getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
- res_state res)
-{
- const HEADER *hp;
- const u_char *cp;
- int n;
- const u_char *eom, *erdata;
- char *bp, **ap, **hap, *ep;
- int type, class, ancount, qdcount;
- int haveanswer, had_error;
- int toobig = 0;
- char tbuf[MAXDNAME];
- const char *tname;
- int (*name_ok)(const char *);
- res_static rs = __res_get_static();
-
- assert(answer != NULL);
- assert(qname != NULL);
-
- tname = qname;
- rs->host.h_name = NULL;
- eom = answer->buf + anslen;
- switch (qtype) {
- case T_A:
- case T_AAAA:
- name_ok = res_hnok;
- break;
- case T_PTR:
- name_ok = res_dnok;
- break;
- default:
- return NULL; /* XXX should be abort(); */
- }
- /*
- * find first satisfactory answer
- */
- hp = &answer->hdr;
- ancount = ntohs(hp->ancount);
- qdcount = ntohs(hp->qdcount);
- bp = rs->hostbuf;
- ep = rs->hostbuf + sizeof rs->hostbuf;
- cp = answer->buf;
- BOUNDED_INCR(HFIXEDSZ);
- if (qdcount != 1) {
- h_errno = NO_RECOVERY;
- return NULL;
- }
- n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
- if ((n < 0) || !(*name_ok)(bp)) {
- h_errno = NO_RECOVERY;
- return NULL;
- }
- BOUNDED_INCR(n + QFIXEDSZ);
- if (qtype == T_A || qtype == T_AAAA) {
- /* res_send() has already verified that the query name is the
- * same as the one we sent; this just gets the expanded name
- * (i.e., with the succeeding search-domain tacked on).
- */
- n = strlen(bp) + 1; /* for the \0 */
- if (n >= MAXHOSTNAMELEN) {
- h_errno = NO_RECOVERY;
- return NULL;
- }
- rs->host.h_name = bp;
- bp += n;
- /* The qname can be abbreviated, but h_name is now absolute. */
- qname = rs->host.h_name;
- }
- ap = rs->host_aliases;
- *ap = NULL;
- rs->host.h_aliases = rs->host_aliases;
- hap = rs->h_addr_ptrs;
- *hap = NULL;
- rs->host.h_addr_list = rs->h_addr_ptrs;
- haveanswer = 0;
- had_error = 0;
- while (ancount-- > 0 && cp < eom && !had_error) {
- n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
- if ((n < 0) || !(*name_ok)(bp)) {
- had_error++;
- continue;
- }
- cp += n; /* name */
- BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
- type = _getshort(cp);
- cp += INT16SZ; /* type */
- class = _getshort(cp);
- cp += INT16SZ + INT32SZ; /* class, TTL */
- n = _getshort(cp);
- cp += INT16SZ; /* len */
- BOUNDS_CHECK(cp, n);
- erdata = cp + n;
- if (class != C_IN) {
- /* XXX - debug? syslog? */
- cp += n;
- continue; /* XXX - had_error++ ? */
- }
- if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
- if (ap >= &rs->host_aliases[MAXALIASES-1])
- continue;
- n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
- if ((n < 0) || !(*name_ok)(tbuf)) {
- had_error++;
- continue;
- }
- cp += n;
- if (cp != erdata) {
- h_errno = NO_RECOVERY;
- return NULL;
- }
- /* Store alias. */
- *ap++ = bp;
- n = strlen(bp) + 1; /* for the \0 */
- if (n >= MAXHOSTNAMELEN) {
- had_error++;
- continue;
- }
- bp += n;
- /* Get canonical name. */
- n = strlen(tbuf) + 1; /* for the \0 */
- if (n > ep - bp || n >= MAXHOSTNAMELEN) {
- had_error++;
- continue;
- }
- strlcpy(bp, tbuf, (size_t)(ep - bp));
- rs->host.h_name = bp;
- bp += n;
- continue;
- }
- if (qtype == T_PTR && type == T_CNAME) {
- n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
- if (n < 0 || !res_dnok(tbuf)) {
- had_error++;
- continue;
- }
- cp += n;
- if (cp != erdata) {
- h_errno = NO_RECOVERY;
- return NULL;
- }
- /* Get canonical name. */
- n = strlen(tbuf) + 1; /* for the \0 */
- if (n > ep - bp || n >= MAXHOSTNAMELEN) {
- had_error++;
- continue;
- }
- strlcpy(bp, tbuf, (size_t)(ep - bp));
- tname = bp;
- bp += n;
- continue;
- }
- if (type != qtype) {
- if (type != T_KEY && type != T_SIG)
- syslog(LOG_NOTICE|LOG_AUTH,
- "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
- qname, p_class(C_IN), p_type(qtype),
- p_type(type));
- cp += n;
- continue; /* XXX - had_error++ ? */
- }
- switch (type) {
- case T_PTR:
- if (strcasecmp(tname, bp) != 0) {
- syslog(LOG_NOTICE|LOG_AUTH,
- AskedForGot, qname, bp);
- cp += n;
- continue; /* XXX - had_error++ ? */
- }
- n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
- if ((n < 0) || !res_hnok(bp)) {
- had_error++;
- break;
- }
-#if MULTI_PTRS_ARE_ALIASES
- cp += n;
- if (cp != erdata) {
- h_errno = NO_RECOVERY;
- return NULL;
- }
- if (!haveanswer)
- rs->host.h_name = bp;
- else if (ap < &rs->host_aliases[MAXALIASES-1])
- *ap++ = bp;
- else
- n = -1;
- if (n != -1) {
- n = strlen(bp) + 1; /* for the \0 */
- if (n >= MAXHOSTNAMELEN) {
- had_error++;
- break;
- }
- bp += n;
- }
- break;
-#else
- rs->host.h_name = bp;
- if (res->options & RES_USE_INET6) {
- n = strlen(bp) + 1; /* for the \0 */
- if (n >= MAXHOSTNAMELEN) {
- had_error++;
- break;
- }
- bp += n;
- map_v4v6_hostent(&rs->host, &bp, ep);
- }
- h_errno = NETDB_SUCCESS;
- return &rs->host;
-#endif
- case T_A:
- case T_AAAA:
- if (strcasecmp(rs->host.h_name, bp) != 0) {
- syslog(LOG_NOTICE|LOG_AUTH,
- AskedForGot, rs->host.h_name, bp);
- cp += n;
- continue; /* XXX - had_error++ ? */
- }
- if (n != rs->host.h_length) {
- cp += n;
- continue;
- }
- if (type == T_AAAA) {
- struct in6_addr in6;
- memcpy(&in6, cp, IN6ADDRSZ);
- if (IN6_IS_ADDR_V4MAPPED(&in6)) {
- cp += n;
- continue;
- }
- }
- if (!haveanswer) {
- int nn;
-
- rs->host.h_name = bp;
- nn = strlen(bp) + 1; /* for the \0 */
- bp += nn;
- }
-
- bp += sizeof(align) -
- (size_t)((u_long)bp % sizeof(align));
-
- if (bp + n >= &rs->hostbuf[sizeof rs->hostbuf]) {
- dprintf("size (%d) too big\n", res, n);
- had_error++;
- continue;
- }
- if (hap >= &rs->h_addr_ptrs[MAXADDRS-1]) {
- if (!toobig++)
- dprintf("Too many addresses (%d)\n",
- res, MAXADDRS);
- cp += n;
- continue;
- }
- (void)memcpy(*hap++ = bp, cp, (size_t)n);
- bp += n;
- cp += n;
- if (cp != erdata) {
- h_errno = NO_RECOVERY;
- return NULL;
- }
- break;
- default:
- abort();
- }
- if (!had_error)
- haveanswer++;
- }
- if (haveanswer) {
- *ap = NULL;
- *hap = NULL;
- /*
- * Note: we sort even if host can take only one address
- * in its return structures - should give it the "best"
- * address in that case, not some random one
- */
- if (res->nsort && haveanswer > 1 && qtype == T_A)
- addrsort(rs->h_addr_ptrs, haveanswer, res);
- if (!rs->host.h_name) {
- n = strlen(qname) + 1; /* for the \0 */
- if (n > ep - bp || n >= MAXHOSTNAMELEN)
- goto no_recovery;
- strlcpy(bp, qname, (size_t)(ep - bp));
- rs->host.h_name = bp;
- bp += n;
- }
- if (res->options & RES_USE_INET6)
- map_v4v6_hostent(&rs->host, &bp, ep);
- h_errno = NETDB_SUCCESS;
- return &rs->host;
- }
- no_recovery:
- h_errno = NO_RECOVERY;
- return NULL;
-}
-
-int
-gethostbyname_r(const char *name, struct hostent *hp, char *buf, size_t buflen,
- struct hostent**result, int *errorp)
-{
- struct hostent *res;
-
- res = gethostbyname(name);
- *errorp = h_errno;
- if (res == NULL) {
- *result = NULL;
- return -1;
- }
- memcpy(hp, res, sizeof *hp);
- *result = hp;
- return 0;
-}
-
-struct hostent *
-gethostbyname(const char *name)
-{
- struct hostent *hp;
- res_state res = __res_get_state();
-
- if (res == NULL)
- return NULL;
-
- assert(name != NULL);
-
- /* try IPv6 first - if that fails do IPv4 */
- if (res->options & RES_USE_INET6) {
- hp = gethostbyname_internal(name, AF_INET6, res, NETID_UNSET, MARK_UNSET);
- if (hp) {
- __res_put_state(res);
- return hp;
- }
- }
- hp = gethostbyname_internal(name, AF_INET, res, NETID_UNSET, MARK_UNSET);
- __res_put_state(res);
- return hp;
-}
-
-struct hostent *
-gethostbyname2(const char *name, int af)
-{
- return android_gethostbynamefornet(name, af, NETID_UNSET, MARK_UNSET);
-}
-
-struct hostent *
-android_gethostbynamefornet(const char *name, int af, unsigned netid, unsigned mark)
-{
- struct hostent *hp;
- res_state res = __res_get_state();
-
- if (res == NULL)
- return NULL;
- hp = gethostbyname_internal(name, af, res, netid, mark);
- __res_put_state(res);
- return hp;
-}
-
-__LIBC_HIDDEN__ FILE* android_open_proxy() {
- const char* cache_mode = getenv("ANDROID_DNS_MODE");
- bool use_proxy = (cache_mode == NULL || strcmp(cache_mode, "local") != 0);
- if (!use_proxy) {
- return NULL;
- }
-
- int s = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
- if (s == -1) {
- return NULL;
- }
-
- const int one = 1;
- setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
-
- struct sockaddr_un proxy_addr;
- memset(&proxy_addr, 0, sizeof(proxy_addr));
- proxy_addr.sun_family = AF_UNIX;
- strlcpy(proxy_addr.sun_path, "/dev/socket/dnsproxyd", sizeof(proxy_addr.sun_path));
-
- if (TEMP_FAILURE_RETRY(connect(s, (const struct sockaddr*) &proxy_addr, sizeof(proxy_addr))) != 0) {
- close(s);
- return NULL;
- }
-
- return fdopen(s, "r+");
-}
-
-static struct hostent *
-android_read_hostent(FILE* proxy)
-{
- uint32_t size;
- char buf[4];
- if (fread(buf, 1, sizeof(buf), proxy) != sizeof(buf)) return NULL;
-
- // This is reading serialized data from system/netd/server/DnsProxyListener.cpp
- // and changes here need to be matched there.
- int result_code = strtol(buf, NULL, 10);
- if (result_code != DnsProxyQueryResult) {
- fread(&size, 1, sizeof(size), proxy);
- return NULL;
- }
-
- if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
- size = ntohl(size);
- res_static rs = __res_get_static();
- memset(&rs->host, 0, sizeof(rs->host));
- char *ptr = rs->hostbuf;
-
- if (fread(ptr, 1, size, proxy) != size) return NULL;
- ptr += size;
- rs->host.h_name = rs->hostbuf;
-
- char **aliases = rs->host_aliases;
- rs->host.h_aliases = rs->host_aliases;
- while (1) {
- if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
- size = ntohl(size);
-
- if (size == 0) {
- *aliases = NULL;
- break;
- }
- if (fread(ptr, 1, size, proxy) != size) return NULL;
- *aliases++ = ptr;
- ptr += size;
- }
-
- if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
- rs->host.h_addrtype = ntohl(size);
-
- if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
- rs->host.h_length = ntohl(size);
-
- char **addrs = rs->h_addr_ptrs;
- rs->host.h_addr_list = rs->h_addr_ptrs;
- while (1) {
- if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
- size = ntohl(size);
- if (size == 0) {
- *addrs = NULL;
- break;
- }
- if (fread(ptr, 1, size, proxy) != size) return NULL;
- *addrs++ = ptr;
- ptr += size;
- }
-
- return &rs->host;
-}
-
-
-static struct hostent *
-gethostbyname_internal_real(const char *name, int af, res_state res)
-{
- const char *cp;
- char *bp, *ep;
- int size;
- struct hostent *hp;
- res_static rs = __res_get_static();
-
- static const ns_dtab dtab[] = {
- NS_FILES_CB(_gethtbyname, NULL)
- { NSSRC_DNS, _dns_gethtbyname, NULL }, /* force -DHESIOD */
- { 0, 0, 0 }
- };
-
- assert(name != NULL);
-
- switch (af) {
- case AF_INET:
- size = INADDRSZ;
- break;
- case AF_INET6:
- size = IN6ADDRSZ;
- break;
- default:
- h_errno = NETDB_INTERNAL;
- errno = EAFNOSUPPORT;
- return NULL;
- }
-
- rs->host.h_addrtype = af;
- rs->host.h_length = size;
-
- /*
- * if there aren't any dots, it could be a user-level alias.
- * this is also done in res_nquery() since we are not the only
- * function that looks up host names.
- */
- if (!strchr(name, '.') && (cp = __hostalias(name)))
- name = cp;
-
- /*
- * disallow names consisting only of digits/dots, unless
- * they end in a dot.
- */
- if (isdigit((u_char) name[0]))
- for (cp = name;; ++cp) {
- if (!*cp) {
- if (*--cp == '.')
- break;
- /*
- * All-numeric, no dot at the end.
- * Fake up a hostent as if we'd actually
- * done a lookup.
- */
- if (inet_pton(af, name,
- (char *)(void *)rs->host_addr) <= 0) {
- h_errno = HOST_NOT_FOUND;
- return NULL;
- }
- strncpy(rs->hostbuf, name, MAXDNAME);
- rs->hostbuf[MAXDNAME] = '\0';
- bp = rs->hostbuf + MAXDNAME;
- ep = rs->hostbuf + sizeof rs->hostbuf;
- rs->host.h_name = rs->hostbuf;
- rs->host.h_aliases = rs->host_aliases;
- rs->host_aliases[0] = NULL;
- rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
- rs->h_addr_ptrs[1] = NULL;
- rs->host.h_addr_list = rs->h_addr_ptrs;
- if (res->options & RES_USE_INET6)
- map_v4v6_hostent(&rs->host, &bp, ep);
- h_errno = NETDB_SUCCESS;
- return &rs->host;
- }
- if (!isdigit((u_char) *cp) && *cp != '.')
- break;
- }
- if ((isxdigit((u_char) name[0]) && strchr(name, ':') != NULL) ||
- name[0] == ':')
- for (cp = name;; ++cp) {
- if (!*cp) {
- if (*--cp == '.')
- break;
- /*
- * All-IPv6-legal, no dot at the end.
- * Fake up a hostent as if we'd actually
- * done a lookup.
- */
- if (inet_pton(af, name,
- (char *)(void *)rs->host_addr) <= 0) {
- h_errno = HOST_NOT_FOUND;
- return NULL;
- }
- strncpy(rs->hostbuf, name, MAXDNAME);
- rs->hostbuf[MAXDNAME] = '\0';
- bp = rs->hostbuf + MAXDNAME;
- ep = rs->hostbuf + sizeof rs->hostbuf;
- rs->host.h_name = rs->hostbuf;
- rs->host.h_aliases = rs->host_aliases;
- rs->host_aliases[0] = NULL;
- rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
- rs->h_addr_ptrs[1] = NULL;
- rs->host.h_addr_list = rs->h_addr_ptrs;
- h_errno = NETDB_SUCCESS;
- return &rs->host;
- }
- if (!isxdigit((u_char) *cp) && *cp != ':' && *cp != '.')
- break;
- }
-
- hp = NULL;
- h_errno = NETDB_INTERNAL;
- if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyname",
- default_dns_files, name, strlen(name), af) != NS_SUCCESS) {
- return NULL;
- }
- h_errno = NETDB_SUCCESS;
- return hp;
-}
-
-
-// very similar in proxy-ness to android_getaddrinfo_proxy
-static struct hostent *
-gethostbyname_internal(const char *name, int af, res_state res, unsigned netid, unsigned mark)
-{
- FILE* proxy = android_open_proxy();
- if (proxy == NULL) {
- // Either we're not supposed to be using the proxy or the proxy is unavailable.
- res_setnetid(res, netid);
- res_setmark(res, mark);
- return gethostbyname_internal_real(name, af, res);
- }
-
- netid = __netdClientDispatch.netIdForResolv(netid);
-
- // This is writing to system/netd/server/DnsProxyListener.cpp and changes
- // here need to be matched there.
- if (fprintf(proxy, "gethostbyname %u %s %d",
- netid,
- name == NULL ? "^" : name,
- af) < 0) {
- fclose(proxy);
- return NULL;
- }
-
- if (fputc(0, proxy) == EOF || fflush(proxy) != 0) {
- fclose(proxy);
- return NULL;
- }
-
- struct hostent* result = android_read_hostent(proxy);
- fclose(proxy);
- return result;
-}
-
-
-static struct hostent *
-android_gethostbyaddrfornet_real(const void *addr, socklen_t len, int af, unsigned netid, unsigned mark) {
- const u_char *uaddr = (const u_char *)addr;
- socklen_t size;
- struct hostent *hp;
- static const ns_dtab dtab[] = {
- NS_FILES_CB(_gethtbyaddr, NULL)
- { NSSRC_DNS, _dns_gethtbyaddr, NULL }, /* force -DHESIOD */
- { 0, 0, 0 }
- };
-
- assert(addr != NULL);
-
- if (af == AF_INET6 && len == NS_IN6ADDRSZ &&
- (IN6_IS_ADDR_LINKLOCAL((const struct in6_addr *)addr) ||
- IN6_IS_ADDR_SITELOCAL((const struct in6_addr *)addr))) {
- h_errno = HOST_NOT_FOUND;
- return NULL;
- }
- if (af == AF_INET6 && len == NS_IN6ADDRSZ &&
- (IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)addr) ||
- IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)addr))) {
- /* Unmap. */
- uaddr += NS_IN6ADDRSZ - NS_INADDRSZ;
- addr = uaddr;
- af = AF_INET;
- len = NS_INADDRSZ;
- }
- switch (af) {
- case AF_INET:
- size = NS_INADDRSZ;
- break;
- case AF_INET6:
- size = NS_IN6ADDRSZ;
- break;
- default:
- errno = EAFNOSUPPORT;
- h_errno = NETDB_INTERNAL;
- return NULL;
- }
- if (size != len) {
- errno = EINVAL;
- h_errno = NETDB_INTERNAL;
- return NULL;
- }
- hp = NULL;
- h_errno = NETDB_INTERNAL;
- if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyaddr",
- default_dns_files, uaddr, len, af, netid, mark) != NS_SUCCESS)
- return NULL;
- h_errno = NETDB_SUCCESS;
- return hp;
-}
-
-__LIBC_HIDDEN__ struct hostent*
-android_gethostbyaddrfornet_proxy(const void* addr, socklen_t len, int af, unsigned netid, unsigned mark) {
- FILE* proxy = android_open_proxy();
- if (proxy == NULL) {
- // Either we're not supposed to be using the proxy or the proxy is unavailable.
- return android_gethostbyaddrfornet_real(addr,len, af, netid, mark);
- }
-
- char buf[INET6_ADDRSTRLEN]; //big enough for IPv4 and IPv6
- const char * addrStr = inet_ntop(af, addr, buf, sizeof(buf));
- if (addrStr == NULL) {
- fclose(proxy);
- return NULL;
- }
-
- netid = __netdClientDispatch.netIdForResolv(netid);
-
- if (fprintf(proxy, "gethostbyaddr %s %d %d %u",
- addrStr, len, af, netid) < 0) {
- fclose(proxy);
- return NULL;
- }
-
- if (fputc(0, proxy) == EOF || fflush(proxy) != 0) {
- fclose(proxy);
- return NULL;
- }
-
- struct hostent *result = android_read_hostent(proxy);
- fclose(proxy);
- return result;
-}
-
-struct hostent *
-android_gethostbyaddrfornet(const void *addr, socklen_t len, int af, unsigned netid, unsigned mark)
-{
- return android_gethostbyaddrfornet_proxy(addr, len, af, netid, mark);
-}
-
-struct hostent *
-gethostbyaddr(const void *addr, socklen_t len, int af)
-{
- return android_gethostbyaddrfornet(addr, len, af, NETID_UNSET, MARK_UNSET);
-}
-
-
-static void
-_sethtent(int f)
-{
- res_static rs = __res_get_static();
- if (rs == NULL) return;
- if (!rs->hostf)
- rs->hostf = fopen(_PATH_HOSTS, "re" );
- else
- rewind(rs->hostf);
- rs->stayopen = f;
-}
-
-static void
-_endhtent(void)
-{
- res_static rs = __res_get_static();
- if (rs == NULL) return;
-
- if (rs->hostf && !rs->stayopen) {
- (void) fclose(rs->hostf);
- rs->hostf = NULL;
- }
-}
-
-static struct hostent *
-_gethtent(void)
-{
- char *p;
- char *cp, **q;
- int af, len;
- res_static rs = __res_get_static();
-
- if (!rs->hostf && !(rs->hostf = fopen(_PATH_HOSTS, "re" ))) {
- h_errno = NETDB_INTERNAL;
- return NULL;
- }
- again:
- if (!(p = fgets(rs->hostbuf, sizeof rs->hostbuf, rs->hostf))) {
- h_errno = HOST_NOT_FOUND;
- return NULL;
- }
- if (*p == '#')
- goto again;
- if (!(cp = strpbrk(p, "#\n")))
- goto again;
- *cp = '\0';
- if (!(cp = strpbrk(p, " \t")))
- goto again;
- *cp++ = '\0';
- if (inet_pton(AF_INET6, p, (char *)(void *)rs->host_addr) > 0) {
- af = AF_INET6;
- len = IN6ADDRSZ;
- } else if (inet_pton(AF_INET, p, (char *)(void *)rs->host_addr) > 0) {
- res_state res = __res_get_state();
- if (res == NULL)
- return NULL;
- if (res->options & RES_USE_INET6) {
- map_v4v6_address((char *)(void *)rs->host_addr,
- (char *)(void *)rs->host_addr);
- af = AF_INET6;
- len = IN6ADDRSZ;
- } else {
- af = AF_INET;
- len = INADDRSZ;
- }
- __res_put_state(res);
- } else {
- goto again;
- }
- /* if this is not something we're looking for, skip it. */
- if (rs->host.h_addrtype != 0 && rs->host.h_addrtype != af)
- goto again;
- if (rs->host.h_length != 0 && rs->host.h_length != len)
- goto again;
- rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
- rs->h_addr_ptrs[1] = NULL;
- rs->host.h_addr_list = rs->h_addr_ptrs;
- rs->host.h_length = len;
- rs->host.h_addrtype = af;
- while (*cp == ' ' || *cp == '\t')
- cp++;
- rs->host.h_name = cp;
- q = rs->host.h_aliases = rs->host_aliases;
- if ((cp = strpbrk(cp, " \t")) != NULL)
- *cp++ = '\0';
- while (cp && *cp) {
- if (*cp == ' ' || *cp == '\t') {
- cp++;
- continue;
- }
- if (q < &rs->host_aliases[MAXALIASES - 1])
- *q++ = cp;
- if ((cp = strpbrk(cp, " \t")) != NULL)
- *cp++ = '\0';
- }
- *q = NULL;
- h_errno = NETDB_SUCCESS;
- return &rs->host;
-}
-
-/*ARGSUSED*/
-int
-_gethtbyname(void *rv, void *cb_data, va_list ap)
-{
- struct hostent *hp;
- const char *name;
- int af;
-
- assert(rv != NULL);
-
- name = va_arg(ap, char *);
- /* NOSTRICT skip len */(void)va_arg(ap, int);
- af = va_arg(ap, int);
-
- hp = NULL;
-#if 0
- {
- res_state res = __res_get_state();
- if (res == NULL)
- return NS_NOTFOUND;
- if (res->options & RES_USE_INET6)
- hp = _gethtbyname2(name, AF_INET6);
- if (hp==NULL)
- hp = _gethtbyname2(name, AF_INET);
- __res_put_state(res);
- }
-#else
- hp = _gethtbyname2(name, af);
-#endif
- *((struct hostent **)rv) = hp;
- if (hp == NULL) {
- h_errno = HOST_NOT_FOUND;
- return NS_NOTFOUND;
- }
- return NS_SUCCESS;
-}
-
-static struct hostent *
-_gethtbyname2(const char *name, int af)
-{
- struct hostent *p;
- char *tmpbuf, *ptr, **cp;
- int num;
- size_t len;
- res_static rs = __res_get_static();
-
- assert(name != NULL);
-
- _sethtent(rs->stayopen);
- ptr = tmpbuf = NULL;
- num = 0;
- while ((p = _gethtent()) != NULL && num < MAXADDRS) {
- if (p->h_addrtype != af)
- continue;
- if (strcasecmp(p->h_name, name) != 0) {
- for (cp = p->h_aliases; *cp != NULL; cp++)
- if (strcasecmp(*cp, name) == 0)
- break;
- if (*cp == NULL) continue;
- }
-
- if (num == 0) {
- size_t bufsize;
- char *src;
-
- bufsize = strlen(p->h_name) + 2 +
- MAXADDRS * p->h_length +
- ALIGNBYTES;
- for (cp = p->h_aliases; *cp != NULL; cp++)
- bufsize += strlen(*cp) + 1;
-
- if ((tmpbuf = malloc(bufsize)) == NULL) {
- h_errno = NETDB_INTERNAL;
- return NULL;
- }
-
- ptr = tmpbuf;
- src = p->h_name;
- while ((*ptr++ = *src++) != '\0');
- for (cp = p->h_aliases; *cp != NULL; cp++) {
- src = *cp;
- while ((*ptr++ = *src++) != '\0');
- }
- *ptr++ = '\0';
-
- ptr = (char *)(void *)ALIGN(ptr);
- }
-
- (void)memcpy(ptr, p->h_addr_list[0], (size_t)p->h_length);
- ptr += p->h_length;
- num++;
- }
- _endhtent();
- if (num == 0) return NULL;
-
- len = ptr - tmpbuf;
- if (len > (sizeof(rs->hostbuf) - ALIGNBYTES)) {
- free(tmpbuf);
- errno = ENOSPC;
- h_errno = NETDB_INTERNAL;
- return NULL;
- }
- ptr = memcpy((void *)ALIGN(rs->hostbuf), tmpbuf, len);
- free(tmpbuf);
-
- rs->host.h_name = ptr;
- while (*ptr++);
-
- cp = rs->host_aliases;
- while (*ptr) {
- *cp++ = ptr;
- while (*ptr++);
- }
- ptr++;
- *cp = NULL;
-
- ptr = (char *)(void *)ALIGN(ptr);
- cp = rs->h_addr_ptrs;
- while (num--) {
- *cp++ = ptr;
- ptr += rs->host.h_length;
- }
- *cp = NULL;
-
- return &rs->host;
-}
-
-/*ARGSUSED*/
-static int
-_gethtbyaddr(void *rv, void *cb_data, va_list ap)
-{
- struct hostent *p;
- const unsigned char *addr;
- int len, af;
- res_static rs = __res_get_static();
-
- assert(rv != NULL);
-
- addr = va_arg(ap, unsigned char *);
- len = va_arg(ap, int);
- af = va_arg(ap, int);
-
- rs->host.h_length = len;
- rs->host.h_addrtype = af;
-
- _sethtent(rs->stayopen);
- while ((p = _gethtent()) != NULL)
- if (p->h_addrtype == af && !memcmp(p->h_addr, addr,
- (size_t)len))
- break;
- _endhtent();
- *((struct hostent **)rv) = p;
- if (p==NULL) {
- h_errno = HOST_NOT_FOUND;
- return NS_NOTFOUND;
- }
- return NS_SUCCESS;
-}
-
-static void
-map_v4v6_address(const char *src, char *dst)
-{
- u_char *p = (u_char *)dst;
- char tmp[INADDRSZ];
- int i;
-
- assert(src != NULL);
- assert(dst != NULL);
-
- /* Stash a temporary copy so our caller can update in place. */
- (void)memcpy(tmp, src, INADDRSZ);
- /* Mark this ipv6 addr as a mapped ipv4. */
- for (i = 0; i < 10; i++)
- *p++ = 0x00;
- *p++ = 0xff;
- *p++ = 0xff;
- /* Retrieve the saved copy and we're done. */
- (void)memcpy((void *)p, tmp, INADDRSZ);
-}
-
-static void
-map_v4v6_hostent(struct hostent *hp, char **bpp, char *ep)
-{
- char **ap;
-
- assert(hp != NULL);
- assert(bpp != NULL);
- assert(ep != NULL);
-
- if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
- return;
- hp->h_addrtype = AF_INET6;
- hp->h_length = IN6ADDRSZ;
- for (ap = hp->h_addr_list; *ap; ap++) {
- int i = sizeof(align) - (size_t)((u_long)*bpp % sizeof(align));
-
- if (ep - *bpp < (i + IN6ADDRSZ)) {
- /* Out of memory. Truncate address list here. XXX */
- *ap = NULL;
- return;
- }
- *bpp += i;
- map_v4v6_address(*ap, *bpp);
- *ap = *bpp;
- *bpp += IN6ADDRSZ;
- }
-}
-
-static void
-addrsort(char **ap, int num, res_state res)
-{
- int i, j;
- char **p;
- short aval[MAXADDRS];
- int needsort = 0;
-
- assert(ap != NULL);
-
- p = ap;
- for (i = 0; i < num; i++, p++) {
- for (j = 0 ; (unsigned)j < res->nsort; j++)
- if (res->sort_list[j].addr.s_addr ==
- (((struct in_addr *)(void *)(*p))->s_addr &
- res->sort_list[j].mask))
- break;
- aval[i] = j;
- if (needsort == 0 && i > 0 && j < aval[i-1])
- needsort = i;
- }
- if (!needsort)
- return;
-
- while (needsort < num) {
- for (j = needsort - 1; j >= 0; j--) {
- if (aval[j] > aval[j+1]) {
- char *hp;
-
- i = aval[j];
- aval[j] = aval[j+1];
- aval[j+1] = i;
-
- hp = ap[j];
- ap[j] = ap[j+1];
- ap[j+1] = hp;
- } else
- break;
- }
- needsort++;
- }
-}
-
-struct hostent *
-gethostent(void)
-{
- res_static rs = __res_get_static();
- rs->host.h_addrtype = 0;
- rs->host.h_length = 0;
- return _gethtent();
-}
-
-/*ARGSUSED*/
-static int
-_dns_gethtbyname(void *rv, void *cb_data, va_list ap)
-{
- querybuf *buf;
- int n, type;
- struct hostent *hp;
- const char *name;
- int af;
- res_state res;
-
- assert(rv != NULL);
-
- name = va_arg(ap, char *);
- /* NOSTRICT skip len */(void)va_arg(ap, int);
- af = va_arg(ap, int);
-
- switch (af) {
- case AF_INET:
- type = T_A;
- break;
- case AF_INET6:
- type = T_AAAA;
- break;
- default:
- return NS_UNAVAIL;
- }
- buf = malloc(sizeof(*buf));
- if (buf == NULL) {
- h_errno = NETDB_INTERNAL;
- return NS_NOTFOUND;
- }
- res = __res_get_state();
- if (res == NULL) {
- free(buf);
- return NS_NOTFOUND;
- }
- n = res_nsearch(res, name, C_IN, type, buf->buf, sizeof(buf->buf));
- if (n < 0) {
- free(buf);
- dprintf("res_nsearch failed (%d)\n", res, n);
- __res_put_state(res);
- return NS_NOTFOUND;
- }
- hp = getanswer(buf, n, name, type, res);
- free(buf);
- __res_put_state(res);
- if (hp == NULL)
- switch (h_errno) {
- case HOST_NOT_FOUND:
- return NS_NOTFOUND;
- case TRY_AGAIN:
- return NS_TRYAGAIN;
- default:
- return NS_UNAVAIL;
- }
- *((struct hostent **)rv) = hp;
- return NS_SUCCESS;
-}
-
-/*ARGSUSED*/
-static int
-_dns_gethtbyaddr(void *rv, void *cb_data, va_list ap)
-{
- char qbuf[MAXDNAME + 1], *qp, *ep;
- int n;
- querybuf *buf;
- struct hostent *hp;
- const unsigned char *uaddr;
- int len, af, advance;
- res_state res;
- unsigned netid, mark;
- res_static rs = __res_get_static();
-
- assert(rv != NULL);
-
- uaddr = va_arg(ap, unsigned char *);
- len = va_arg(ap, int);
- af = va_arg(ap, int);
- netid = va_arg(ap, unsigned);
- mark = va_arg(ap, unsigned);
-
- switch (af) {
- case AF_INET:
- (void)snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u.in-addr.arpa",
- (uaddr[3] & 0xff), (uaddr[2] & 0xff),
- (uaddr[1] & 0xff), (uaddr[0] & 0xff));
- break;
-
- case AF_INET6:
- qp = qbuf;
- ep = qbuf + sizeof(qbuf) - 1;
- for (n = IN6ADDRSZ - 1; n >= 0; n--) {
- advance = snprintf(qp, (size_t)(ep - qp), "%x.%x.",
- uaddr[n] & 0xf,
- ((unsigned int)uaddr[n] >> 4) & 0xf);
- if (advance > 0 && qp + advance < ep)
- qp += advance;
- else {
- h_errno = NETDB_INTERNAL;
- return NS_NOTFOUND;
- }
- }
- if (strlcat(qbuf, "ip6.arpa", sizeof(qbuf)) >= sizeof(qbuf)) {
- h_errno = NETDB_INTERNAL;
- return NS_NOTFOUND;
- }
- break;
- default:
- abort();
- }
-
- buf = malloc(sizeof(*buf));
- if (buf == NULL) {
- h_errno = NETDB_INTERNAL;
- return NS_NOTFOUND;
- }
- res = __res_get_state();
- if (res == NULL) {
- free(buf);
- return NS_NOTFOUND;
- }
- res_setnetid(res, netid);
- res_setmark(res, mark);
- n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, sizeof(buf->buf));
- if (n < 0) {
- free(buf);
- dprintf("res_nquery failed (%d)\n", res, n);
- __res_put_state(res);
- return NS_NOTFOUND;
- }
- hp = getanswer(buf, n, qbuf, T_PTR, res);
- free(buf);
- if (hp == NULL) {
- __res_put_state(res);
- switch (h_errno) {
- case HOST_NOT_FOUND:
- return NS_NOTFOUND;
- case TRY_AGAIN:
- return NS_TRYAGAIN;
- default:
- return NS_UNAVAIL;
- }
- }
- hp->h_addrtype = af;
- hp->h_length = len;
- (void)memcpy(rs->host_addr, uaddr, (size_t)len);
- rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
- rs->h_addr_ptrs[1] = NULL;
- if (af == AF_INET && (res->options & RES_USE_INET6)) {
- map_v4v6_address((char *)(void *)rs->host_addr,
- (char *)(void *)rs->host_addr);
- hp->h_addrtype = AF_INET6;
- hp->h_length = IN6ADDRSZ;
- }
-
- __res_put_state(res);
- *((struct hostent **)rv) = hp;
- h_errno = NETDB_SUCCESS;
- return NS_SUCCESS;
-}
diff --git a/libc/dns/include/hostent.h b/libc/dns/include/hostent.h
new file mode 100644
index 0000000..8b9a637
--- /dev/null
+++ b/libc/dns/include/hostent.h
@@ -0,0 +1,93 @@
+/* $NetBSD: hostent.h,v 1.2 2013/08/27 09:56:12 christos Exp $ */
+
+/*-
+ * Copyright (c) 2013 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+#ifndef _DNS_NET_HOSTENT_H
+#define _DNS_NET_HOSTENT_H
+
+#include <stdio.h>
+#include <netdb.h>
+#include <stdarg.h>
+
+/*
+ * These are not being advertised because the interfaces are non-standard.
+ * There are versions by linux, aix, qnx, sun, etc. Our versions are used
+ * internally to provide thread safety; they mostly resemble qnx.
+ */
+void sethostent_r(FILE **);
+struct hostent *netbsd_gethostent_r(FILE *, struct hostent *, char *, size_t, int *);
+void endhostent_r(FILE **);
+
+/*
+ * The following are internal API's and are used only for testing.
+ */
+struct getnamaddr {
+ struct hostent *hp;
+ char *buf;
+ size_t buflen;
+ int *he;
+};
+
+/* /etc/hosts lookup */
+int _hf_gethtbyaddr(void *, void *, va_list);
+int _hf_gethtbyname(void *, void *, va_list);
+
+#ifdef YP
+/* NIS lookup */
+int _yp_gethtbyaddr(void *, void *, va_list);
+int _yp_gethtbyname(void *, void *, va_list);
+#endif
+
+#define HENT_ARRAY(dst, anum, ptr, len) \
+ do { \
+ size_t _len = (anum + 1) * sizeof(*dst); \
+ if (_len > len) \
+ goto nospc; \
+ dst = (void *)ptr; \
+ ptr += _len; \
+ len -= _len; \
+ } while (/*CONSTCOND*/0)
+
+#define HENT_COPY(dst, src, slen, ptr, len) \
+ do { \
+ if ((size_t)slen > len) \
+ goto nospc; \
+ memcpy(ptr, src, (size_t)slen); \
+ dst = ptr; \
+ ptr += slen; \
+ len -= slen; \
+ } while (/* CONSTCOND */0)
+
+#define HENT_SCOPY(dst, src, ptr, len) \
+ do { \
+ size_t _len = strlen(src) + 1; \
+ HENT_COPY(dst, src, _len, ptr, len); \
+ } while (/* CONSTCOND */0)
+
+#endif /* _DNS_NET_HOSTENT_H */
diff --git a/libc/dns/net/gethnamaddr.c b/libc/dns/net/gethnamaddr.c
new file mode 100644
index 0000000..8f5800a
--- /dev/null
+++ b/libc/dns/net/gethnamaddr.c
@@ -0,0 +1,1631 @@
+/* $NetBSD: gethnamaddr.c,v 1.91 2014/06/19 15:08:18 christos Exp $ */
+
+/*
+ * ++Copyright++ 1985, 1988, 1993
+ * -
+ * Copyright (c) 1985, 1988, 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. 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.
+ * -
+ * --Copyright--
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include "NetdClientDispatch.h"
+#include "resolv_netid.h"
+#include "resolv_private.h"
+#include "resolv_cache.h"
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <strings.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#define ALIGNBYTES (sizeof(uintptr_t) - 1)
+#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)
+
+#ifndef LOG_AUTH
+# define LOG_AUTH 0
+#endif
+
+#define MULTI_PTRS_ARE_ALIASES 1 /* XXX - experimental */
+
+#include "nsswitch.h"
+#include <stdlib.h>
+#include <string.h>
+
+#include "hostent.h"
+
+#define maybe_ok(res, nm, ok) (((res)->options & RES_NOCHECKNAME) != 0U || \
+ (ok)(nm) != 0)
+#define maybe_hnok(res, hn) maybe_ok((res), (hn), res_hnok)
+#define maybe_dnok(res, dn) maybe_ok((res), (dn), res_dnok)
+
+#define addalias(d, s, arr, siz) do { \
+ if (d >= &arr[siz]) { \
+ char **xptr = realloc(arr, (siz + 10) * sizeof(*arr)); \
+ if (xptr == NULL) \
+ goto nospc; \
+ d = xptr + (d - arr); \
+ arr = xptr; \
+ siz += 10; \
+ } \
+ *d++ = s; \
+} while (/*CONSTCOND*/0)
+
+#define setup(arr, siz) do { \
+ arr = malloc((siz = 10) * sizeof(*arr)); \
+ if (arr == NULL) \
+ goto nospc; \
+} while (/*CONSTCOND*/0)
+
+// This should be synchronized to ResponseCode.h
+static const int DnsProxyQueryResult = 222;
+
+static const char AskedForGot[] =
+ "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
+
+#define MAXPACKET (64*1024)
+
+typedef union {
+ HEADER hdr;
+ u_char buf[MAXPACKET];
+} querybuf;
+
+typedef union {
+ int32_t al;
+ char ac;
+} align;
+
+#ifdef DEBUG
+static void debugprintf(const char *, res_state, ...)
+ __attribute__((__format__(__printf__, 1, 3)));
+#endif
+static struct hostent *getanswer(const querybuf *, int, const char *, int,
+ res_state, struct hostent *, char *, size_t, int *);
+static void map_v4v6_address(const char *, char *);
+static void map_v4v6_hostent(struct hostent *, char **, char *);
+static void addrsort(char **, int, res_state);
+
+void ht_sethostent(int);
+void ht_endhostent(void);
+struct hostent *ht_gethostbyname(char *);
+struct hostent *ht_gethostbyaddr(const char *, int, int);
+void dns_service(void);
+#undef dn_skipname
+int dn_skipname(const u_char *, const u_char *);
+static int _dns_gethtbyaddr(void *, void *, va_list);
+static int _dns_gethtbyname(void *, void *, va_list);
+
+static struct hostent *gethostbyname_internal(const char *, int, res_state,
+ struct hostent *, char *, size_t, int *, unsigned, unsigned);
+static struct hostent* android_gethostbyaddrfornet_proxy_internal(const void*, socklen_t,
+ int, struct hostent *, char *, size_t, int *, unsigned, unsigned);
+
+static const ns_src default_dns_files[] = {
+ { NSSRC_FILES, NS_SUCCESS },
+ { NSSRC_DNS, NS_SUCCESS },
+ { 0, 0 }
+};
+
+
+#ifdef DEBUG
+static void
+debugprintf(const char *msg, res_state res, ...)
+{
+ _DIAGASSERT(msg != NULL);
+
+ if (res->options & RES_DEBUG) {
+ int save = errno;
+ va_list ap;
+
+ va_start (ap, res);
+ vprintf(msg, ap);
+ va_end (ap);
+
+ errno = save;
+ }
+}
+#else
+# define debugprintf(msg, res, num) /*nada*/
+#endif
+
+#define BOUNDED_INCR(x) \
+ do { \
+ cp += (x); \
+ if (cp > eom) \
+ goto no_recovery; \
+ } while (/*CONSTCOND*/0)
+
+#define BOUNDS_CHECK(ptr, count) \
+ do { \
+ if ((ptr) + (count) > eom) \
+ goto no_recovery; \
+ } while (/*CONSTCOND*/0)
+
+static struct hostent *
+getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
+ res_state res, struct hostent *hent, char *buf, size_t buflen, int *he)
+{
+ const HEADER *hp;
+ const u_char *cp;
+ int n;
+ size_t qlen;
+ const u_char *eom, *erdata;
+ char *bp, **ap, **hap, *ep;
+ int type, class, ancount, qdcount;
+ int haveanswer, had_error;
+ int toobig = 0;
+ char tbuf[MAXDNAME];
+ char **aliases;
+ size_t maxaliases;
+ char *addr_ptrs[MAXADDRS];
+ const char *tname;
+ int (*name_ok)(const char *);
+
+ _DIAGASSERT(answer != NULL);
+ _DIAGASSERT(qname != NULL);
+
+ tname = qname;
+ hent->h_name = NULL;
+ eom = answer->buf + anslen;
+ switch (qtype) {
+ case T_A:
+ case T_AAAA:
+ name_ok = res_hnok;
+ break;
+ case T_PTR:
+ name_ok = res_dnok;
+ break;
+ default:
+ *he = NO_RECOVERY;
+ return NULL; /* XXX should be abort(); */
+ }
+
+ setup(aliases, maxaliases);
+ /*
+ * find first satisfactory answer
+ */
+ hp = &answer->hdr;
+ ancount = ntohs(hp->ancount);
+ qdcount = ntohs(hp->qdcount);
+ bp = buf;
+ ep = buf + buflen;
+ cp = answer->buf;
+ BOUNDED_INCR(HFIXEDSZ);
+ if (qdcount != 1)
+ goto no_recovery;
+
+ n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp));
+ if ((n < 0) || !maybe_ok(res, bp, name_ok))
+ goto no_recovery;
+
+ BOUNDED_INCR(n + QFIXEDSZ);
+ if (qtype == T_A || qtype == T_AAAA) {
+ /* res_send() has already verified that the query name is the
+ * same as the one we sent; this just gets the expanded name
+ * (i.e., with the succeeding search-domain tacked on).
+ */
+ n = (int)strlen(bp) + 1; /* for the \0 */
+ if (n >= MAXHOSTNAMELEN)
+ goto no_recovery;
+ hent->h_name = bp;
+ bp += n;
+ /* The qname can be abbreviated, but h_name is now absolute. */
+ qname = hent->h_name;
+ }
+ hent->h_aliases = ap = aliases;
+ hent->h_addr_list = hap = addr_ptrs;
+ *ap = NULL;
+ *hap = NULL;
+ haveanswer = 0;
+ had_error = 0;
+ while (ancount-- > 0 && cp < eom && !had_error) {
+ n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp));
+ if ((n < 0) || !maybe_ok(res, bp, name_ok)) {
+ had_error++;
+ continue;
+ }
+ cp += n; /* name */
+ BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
+ type = _getshort(cp);
+ cp += INT16SZ; /* type */
+ class = _getshort(cp);
+ cp += INT16SZ + INT32SZ; /* class, TTL */
+ n = _getshort(cp);
+ cp += INT16SZ; /* len */
+ BOUNDS_CHECK(cp, n);
+ erdata = cp + n;
+ if (class != C_IN) {
+ /* XXX - debug? syslog? */
+ cp += n;
+ continue; /* XXX - had_error++ ? */
+ }
+ if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
+ n = dn_expand(answer->buf, eom, cp, tbuf,
+ (int)sizeof tbuf);
+ if ((n < 0) || !maybe_ok(res, tbuf, name_ok)) {
+ had_error++;
+ continue;
+ }
+ cp += n;
+ if (cp != erdata)
+ goto no_recovery;
+ /* Store alias. */
+ addalias(ap, bp, aliases, maxaliases);
+ n = (int)strlen(bp) + 1; /* for the \0 */
+ if (n >= MAXHOSTNAMELEN) {
+ had_error++;
+ continue;
+ }
+ bp += n;
+ /* Get canonical name. */
+ n = (int)strlen(tbuf) + 1; /* for the \0 */
+ if (n > ep - bp || n >= MAXHOSTNAMELEN) {
+ had_error++;
+ continue;
+ }
+ strlcpy(bp, tbuf, (size_t)(ep - bp));
+ hent->h_name = bp;
+ bp += n;
+ continue;
+ }
+ if (qtype == T_PTR && type == T_CNAME) {
+ n = dn_expand(answer->buf, eom, cp, tbuf,
+ (int)sizeof tbuf);
+ if (n < 0 || !maybe_dnok(res, tbuf)) {
+ had_error++;
+ continue;
+ }
+ cp += n;
+ if (cp != erdata)
+ goto no_recovery;
+ /* Get canonical name. */
+ n = (int)strlen(tbuf) + 1; /* for the \0 */
+ if (n > ep - bp || n >= MAXHOSTNAMELEN) {
+ had_error++;
+ continue;
+ }
+ strlcpy(bp, tbuf, (size_t)(ep - bp));
+ tname = bp;
+ bp += n;
+ continue;
+ }
+ if (type != qtype) {
+ if (type != T_KEY && type != T_SIG)
+ syslog(LOG_NOTICE|LOG_AUTH,
+ "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
+ qname, p_class(C_IN), p_type(qtype),
+ p_type(type));
+ cp += n;
+ continue; /* XXX - had_error++ ? */
+ }
+ switch (type) {
+ case T_PTR:
+ if (strcasecmp(tname, bp) != 0) {
+ syslog(LOG_NOTICE|LOG_AUTH,
+ AskedForGot, qname, bp);
+ cp += n;
+ continue; /* XXX - had_error++ ? */
+ }
+ n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp));
+ if ((n < 0) || !maybe_hnok(res, bp)) {
+ had_error++;
+ break;
+ }
+#if MULTI_PTRS_ARE_ALIASES
+ cp += n;
+ if (cp != erdata)
+ goto no_recovery;
+ if (!haveanswer)
+ hent->h_name = bp;
+ else
+ addalias(ap, bp, aliases, maxaliases);
+ if (n != -1) {
+ n = (int)strlen(bp) + 1; /* for the \0 */
+ if (n >= MAXHOSTNAMELEN) {
+ had_error++;
+ break;
+ }
+ bp += n;
+ }
+ break;
+#else
+ hent->h_name = bp;
+ if (res->options & RES_USE_INET6) {
+ n = strlen(bp) + 1; /* for the \0 */
+ if (n >= MAXHOSTNAMELEN) {
+ had_error++;
+ break;
+ }
+ bp += n;
+ map_v4v6_hostent(hent, &bp, ep);
+ }
+ goto success;
+#endif
+ case T_A:
+ case T_AAAA:
+ if (strcasecmp(hent->h_name, bp) != 0) {
+ syslog(LOG_NOTICE|LOG_AUTH,
+ AskedForGot, hent->h_name, bp);
+ cp += n;
+ continue; /* XXX - had_error++ ? */
+ }
+ if (n != hent->h_length) {
+ cp += n;
+ continue;
+ }
+ if (type == T_AAAA) {
+ struct in6_addr in6;
+ memcpy(&in6, cp, NS_IN6ADDRSZ);
+ if (IN6_IS_ADDR_V4MAPPED(&in6)) {
+ cp += n;
+ continue;
+ }
+ }
+ if (!haveanswer) {
+ int nn;
+
+ hent->h_name = bp;
+ nn = (int)strlen(bp) + 1; /* for the \0 */
+ bp += nn;
+ }
+
+ bp += sizeof(align) -
+ (size_t)((u_long)bp % sizeof(align));
+
+ if (bp + n >= ep) {
+ debugprintf("size (%d) too big\n", res, n);
+ had_error++;
+ continue;
+ }
+ if (hap >= &addr_ptrs[MAXADDRS - 1]) {
+ if (!toobig++) {
+ debugprintf("Too many addresses (%d)\n",
+ res, MAXADDRS);
+ }
+ cp += n;
+ continue;
+ }
+ (void)memcpy(*hap++ = bp, cp, (size_t)n);
+ bp += n;
+ cp += n;
+ if (cp != erdata)
+ goto no_recovery;
+ break;
+ default:
+ abort();
+ }
+ if (!had_error)
+ haveanswer++;
+ }
+ if (haveanswer) {
+ *ap = NULL;
+ *hap = NULL;
+ /*
+ * Note: we sort even if host can take only one address
+ * in its return structures - should give it the "best"
+ * address in that case, not some random one
+ */
+ if (res->nsort && haveanswer > 1 && qtype == T_A)
+ addrsort(addr_ptrs, haveanswer, res);
+ if (!hent->h_name) {
+ n = (int)strlen(qname) + 1; /* for the \0 */
+ if (n > ep - bp || n >= MAXHOSTNAMELEN)
+ goto no_recovery;
+ strlcpy(bp, qname, (size_t)(ep - bp));
+ hent->h_name = bp;
+ bp += n;
+ }
+ if (res->options & RES_USE_INET6)
+ map_v4v6_hostent(hent, &bp, ep);
+ goto success;
+ }
+no_recovery:
+ free(aliases);
+ *he = NO_RECOVERY;
+ return NULL;
+success:
+ bp = (char *)ALIGN(bp);
+ n = (int)(ap - aliases);
+ qlen = (n + 1) * sizeof(*hent->h_aliases);
+ if ((size_t)(ep - bp) < qlen)
+ goto nospc;
+ hent->h_aliases = (void *)bp;
+ memcpy(bp, aliases, qlen);
+ free(aliases);
+ aliases = NULL;
+
+ bp += qlen;
+ n = (int)(hap - addr_ptrs);
+ qlen = (n + 1) * sizeof(*hent->h_addr_list);
+ if ((size_t)(ep - bp) < qlen)
+ goto nospc;
+ hent->h_addr_list = (void *)bp;
+ memcpy(bp, addr_ptrs, qlen);
+ *he = NETDB_SUCCESS;
+ return hent;
+nospc:
+ free(aliases);
+ errno = ENOSPC;
+ *he = NETDB_INTERNAL;
+ return NULL;
+}
+
+/* The prototype of gethostbyname_r is from glibc, not that in netbsd. */
+int
+gethostbyname_r(const char *name, struct hostent *hp, char *buf, size_t buflen,
+ struct hostent **result, int *errorp)
+{
+ res_state res = __res_get_state();
+
+ if (res == NULL) {
+ *result = NULL;
+ *errorp = NETDB_INTERNAL;
+ return -1;
+ }
+
+ _DIAGASSERT(name != NULL);
+
+ if (res->options & RES_USE_INET6) {
+ *result = gethostbyname_internal(name, AF_INET6, res, hp, buf, buflen, errorp, NETID_UNSET,
+ MARK_UNSET);
+ if (*result) {
+ __res_put_state(res);
+ return 0;
+ }
+ }
+ *result = gethostbyname_internal(name, AF_INET, res, hp, buf, buflen, errorp, NETID_UNSET,
+ MARK_UNSET);
+ __res_put_state(res);
+ if (!*result && errno == ENOSPC) {
+ errno = ERANGE;
+ return ERANGE; /* Return error as in linux manual page. */
+ }
+ return (*result) ? 0 : -1;
+}
+
+/* The prototype of gethostbyname2_r is from glibc, not that in netbsd. */
+int
+gethostbyname2_r(const char *name, int af, struct hostent *hp, char *buf,
+ size_t buflen, struct hostent **result, int *errorp)
+{
+ res_state res = __res_get_state();
+
+ if (res == NULL) {
+ *result = NULL;
+ *errorp = NETDB_INTERNAL;
+ return -1;
+ }
+ *result = gethostbyname_internal(name, af, res, hp, buf, buflen, errorp, NETID_UNSET,
+ MARK_UNSET);
+ __res_put_state(res);
+ if (!*result && errno == ENOSPC) {
+ errno = ERANGE;
+ return ERANGE;
+ }
+ return (*result) ? 0 : -1;
+}
+
+__LIBC_HIDDEN__ FILE* android_open_proxy() {
+ const char* cache_mode = getenv("ANDROID_DNS_MODE");
+ bool use_proxy = (cache_mode == NULL || strcmp(cache_mode, "local") != 0);
+ if (!use_proxy) {
+ return NULL;
+ }
+
+ int s = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ if (s == -1) {
+ return NULL;
+ }
+
+ const int one = 1;
+ setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
+
+ struct sockaddr_un proxy_addr;
+ memset(&proxy_addr, 0, sizeof(proxy_addr));
+ proxy_addr.sun_family = AF_UNIX;
+ strlcpy(proxy_addr.sun_path, "/dev/socket/dnsproxyd", sizeof(proxy_addr.sun_path));
+
+ if (TEMP_FAILURE_RETRY(connect(s, (const struct sockaddr*) &proxy_addr, sizeof(proxy_addr))) != 0) {
+ close(s);
+ return NULL;
+ }
+
+ return fdopen(s, "r+");
+}
+
+static struct hostent *
+android_read_hostent(FILE* proxy, struct hostent* hp, char* hbuf, size_t hbuflen, int *he)
+{
+ uint32_t size;
+ char buf[4];
+ if (fread(buf, 1, sizeof(buf), proxy) != sizeof(buf)) return NULL;
+
+ // This is reading serialized data from system/netd/server/DnsProxyListener.cpp
+ // and changes here need to be matched there.
+ int result_code = strtol(buf, NULL, 10);
+ if (result_code != DnsProxyQueryResult) {
+ fread(&size, 1, sizeof(size), proxy);
+ *he = HOST_NOT_FOUND;
+ return NULL;
+ }
+
+ if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
+ size = ntohl(size);
+
+ memset(hp, 0, sizeof(*hp));
+ char *ptr = hbuf;
+ char *hbuf_end = hbuf + hbuflen;
+
+ if (ptr + size > hbuf_end) {
+ goto nospc;
+ }
+ if (fread(ptr, 1, size, proxy) != size) return NULL;
+ hp->h_name = ptr;
+ ptr += size;
+
+ char *aliases_ptrs[MAXALIASES];
+ char **aliases = &aliases_ptrs[0];
+
+ while (1) {
+ if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
+ size = ntohl(size);
+
+ if (size == 0) {
+ *aliases = NULL;
+ break;
+ }
+ if (ptr + size > hbuf_end) {
+ goto nospc;
+ }
+ if (fread(ptr, 1, size, proxy) != size) return NULL;
+ if (aliases < &aliases_ptrs[MAXALIASES - 1]) {
+ *aliases++ = ptr;
+ }
+ ptr += size;
+ }
+
+ int aliases_len = ((int)(aliases - aliases_ptrs) + 1) * sizeof(*hp->h_aliases);
+ if (ptr + aliases_len > hbuf_end) {
+ goto nospc;
+ }
+ hp->h_aliases = (void*)ptr;
+ memcpy(ptr, aliases_ptrs, aliases_len);
+ ptr += aliases_len;
+
+ if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
+ hp->h_addrtype = ntohl(size);
+
+ if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
+ hp->h_length = ntohl(size);
+
+ char *addr_ptrs[MAXADDRS];
+ char **addr_p = &addr_ptrs[0];
+
+ while (1) {
+ if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
+ size = ntohl(size);
+ if (size == 0) {
+ *addr_p = NULL;
+ break;
+ }
+ if (ptr + size > hbuf_end) {
+ goto nospc;
+ }
+ if (fread(ptr, 1, size, proxy) != size) return NULL;
+ if (addr_p < &addr_ptrs[MAXADDRS - 1]) {
+ *addr_p++ = ptr;
+ }
+ ptr += size;
+ }
+
+ int addrs_len = ((int)(addr_p - addr_ptrs) + 1) * sizeof(*hp->h_addr_list);
+ if (ptr + addrs_len > hbuf_end) {
+ goto nospc;
+ }
+ hp->h_addr_list = (void*)ptr;
+ memcpy(ptr, addr_ptrs, addrs_len);
+ *he = NETDB_SUCCESS;
+ return hp;
+
+nospc:
+ *he = NETDB_INTERNAL;
+ errno = ENOSPC;
+ return NULL;
+}
+
+static struct hostent *
+gethostbyname_internal_real(const char *name, int af, res_state res, struct hostent *hp, char *buf,
+ size_t buflen, int *he)
+{
+ const char *cp;
+ struct getnamaddr info;
+ char hbuf[MAXHOSTNAMELEN];
+ size_t size;
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_hf_gethtbyname, NULL)
+ { NSSRC_DNS, _dns_gethtbyname, NULL }, /* force -DHESIOD */
+ NS_NIS_CB(_yp_gethtbyname, NULL)
+ NS_NULL_CB
+ };
+
+ _DIAGASSERT(name != NULL);
+
+ switch (af) {
+ case AF_INET:
+ size = NS_INADDRSZ;
+ break;
+ case AF_INET6:
+ size = NS_IN6ADDRSZ;
+ break;
+ default:
+ *he = NETDB_INTERNAL;
+ errno = EAFNOSUPPORT;
+ return NULL;
+ }
+ if (buflen < size)
+ goto nospc;
+
+ hp->h_addrtype = af;
+ hp->h_length = (int)size;
+
+ /*
+ * if there aren't any dots, it could be a user-level alias.
+ * this is also done in res_nquery() since we are not the only
+ * function that looks up host names.
+ */
+ if (!strchr(name, '.') && (cp = res_hostalias(res, name,
+ hbuf, sizeof(hbuf))))
+ name = cp;
+
+ /*
+ * disallow names consisting only of digits/dots, unless
+ * they end in a dot.
+ */
+ if (isdigit((u_char) name[0]))
+ for (cp = name;; ++cp) {
+ if (!*cp) {
+ if (*--cp == '.')
+ break;
+ /*
+ * All-numeric, no dot at the end.
+ * Fake up a hostent as if we'd actually
+ * done a lookup.
+ */
+ goto fake;
+ }
+ if (!isdigit((u_char) *cp) && *cp != '.')
+ break;
+ }
+ if ((isxdigit((u_char) name[0]) && strchr(name, ':') != NULL) ||
+ name[0] == ':')
+ for (cp = name;; ++cp) {
+ if (!*cp) {
+ if (*--cp == '.')
+ break;
+ /*
+ * All-IPv6-legal, no dot at the end.
+ * Fake up a hostent as if we'd actually
+ * done a lookup.
+ */
+ goto fake;
+ }
+ if (!isxdigit((u_char) *cp) && *cp != ':' && *cp != '.')
+ break;
+ }
+
+ *he = NETDB_INTERNAL;
+ info.hp = hp;
+ info.buf = buf;
+ info.buflen = buflen;
+ info.he = he;
+ if (nsdispatch(&info, dtab, NSDB_HOSTS, "gethostbyname",
+ default_dns_files, name, strlen(name), af) != NS_SUCCESS)
+ return NULL;
+ *he = NETDB_SUCCESS;
+ return hp;
+nospc:
+ *he = NETDB_INTERNAL;
+ errno = ENOSPC;
+ return NULL;
+fake:
+ HENT_ARRAY(hp->h_addr_list, 1, buf, buflen);
+ HENT_ARRAY(hp->h_aliases, 0, buf, buflen);
+
+ hp->h_aliases[0] = NULL;
+ if (size > buflen)
+ goto nospc;
+
+ if (inet_pton(af, name, buf) <= 0) {
+ *he = HOST_NOT_FOUND;
+ return NULL;
+ }
+ hp->h_addr_list[0] = buf;
+ hp->h_addr_list[1] = NULL;
+ buf += size;
+ buflen -= size;
+ HENT_SCOPY(hp->h_name, name, buf, buflen);
+ if (res->options & RES_USE_INET6)
+ map_v4v6_hostent(hp, &buf, buf + buflen);
+ *he = NETDB_SUCCESS;
+ return hp;
+}
+
+// very similar in proxy-ness to android_getaddrinfo_proxy
+static struct hostent *
+gethostbyname_internal(const char *name, int af, res_state res, struct hostent *hp, char *hbuf,
+ size_t hbuflen, int *errorp, unsigned netid, unsigned mark)
+{
+ FILE* proxy = android_open_proxy();
+ if (proxy == NULL) {
+ // Either we're not supposed to be using the proxy or the proxy is unavailable.
+ res_setnetid(res, netid);
+ res_setmark(res, mark);
+ return gethostbyname_internal_real(name, af, res, hp, hbuf, hbuflen, errorp);
+ }
+
+ netid = __netdClientDispatch.netIdForResolv(netid);
+
+ // This is writing to system/netd/server/DnsProxyListener.cpp and changes
+ // here need to be matched there.
+ if (fprintf(proxy, "gethostbyname %u %s %d",
+ netid,
+ name == NULL ? "^" : name,
+ af) < 0) {
+ fclose(proxy);
+ return NULL;
+ }
+
+ if (fputc(0, proxy) == EOF || fflush(proxy) != 0) {
+ fclose(proxy);
+ return NULL;
+ }
+
+ struct hostent* result = android_read_hostent(proxy, hp, hbuf, hbuflen, errorp);
+ fclose(proxy);
+ return result;
+}
+
+/* The prototype of gethostbyaddr_r is from glibc, not that in netbsd. */
+int gethostbyaddr_r(const void *addr, socklen_t len, int af, struct hostent *hp, char *buf,
+ size_t buflen, struct hostent **result, int *h_errnop)
+{
+ *result = android_gethostbyaddrfornet_proxy_internal(addr, len, af, hp, buf, buflen, h_errnop,
+ NETID_UNSET, MARK_UNSET);
+ if (!*result && errno == ENOSPC) {
+ errno = ERANGE;
+ return ERANGE;
+ }
+ return (*result) ? 0 : -1;
+}
+
+static struct hostent *
+android_gethostbyaddrfornet_real(const void *addr, socklen_t len, int af, struct hostent *hp,
+ char *buf, size_t buflen, int *he, unsigned netid, unsigned mark)
+{
+ const u_char *uaddr = (const u_char *)addr;
+ socklen_t size;
+ struct getnamaddr info;
+ static const ns_dtab dtab[] = {
+ NS_FILES_CB(_hf_gethtbyaddr, NULL)
+ { NSSRC_DNS, _dns_gethtbyaddr, NULL }, /* force -DHESIOD */
+ NS_NIS_CB(_yp_gethtbyaddr, NULL)
+ NS_NULL_CB
+ };
+
+ _DIAGASSERT(addr != NULL);
+
+ if (af == AF_INET6 && len == NS_IN6ADDRSZ &&
+ (IN6_IS_ADDR_LINKLOCAL((const struct in6_addr *)addr) ||
+ IN6_IS_ADDR_SITELOCAL((const struct in6_addr *)addr))) {
+ *he = HOST_NOT_FOUND;
+ return NULL;
+ }
+ if (af == AF_INET6 && len == NS_IN6ADDRSZ &&
+ (IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)addr) ||
+ IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)addr))) {
+ /* Unmap. */
+ uaddr += NS_IN6ADDRSZ - NS_INADDRSZ;
+ addr = uaddr;
+ af = AF_INET;
+ len = NS_INADDRSZ;
+ }
+ switch (af) {
+ case AF_INET:
+ size = NS_INADDRSZ;
+ break;
+ case AF_INET6:
+ size = NS_IN6ADDRSZ;
+ break;
+ default:
+ errno = EAFNOSUPPORT;
+ *he = NETDB_INTERNAL;
+ return NULL;
+ }
+ if (size != len) {
+ errno = EINVAL;
+ *he = NETDB_INTERNAL;
+ return NULL;
+ }
+ info.hp = hp;
+ info.buf = buf;
+ info.buflen = buflen;
+ info.he = he;
+ *he = NETDB_INTERNAL;
+ if (nsdispatch(&info, dtab, NSDB_HOSTS, "gethostbyaddr",
+ default_dns_files, uaddr, len, af, netid, mark) != NS_SUCCESS)
+ return NULL;
+ *he = NETDB_SUCCESS;
+ return hp;
+}
+
+static struct hostent*
+android_gethostbyaddrfornet_proxy_internal(const void* addr, socklen_t len, int af,
+ struct hostent *hp, char *hbuf, size_t hbuflen, int *he,
+ unsigned netid, unsigned mark)
+{
+ FILE* proxy = android_open_proxy();
+ if (proxy == NULL) {
+ // Either we're not supposed to be using the proxy or the proxy is unavailable.
+ return android_gethostbyaddrfornet_real(addr,len, af, hp, hbuf, hbuflen, he, netid, mark);
+ }
+
+ char buf[INET6_ADDRSTRLEN]; //big enough for IPv4 and IPv6
+ const char * addrStr = inet_ntop(af, addr, buf, sizeof(buf));
+ if (addrStr == NULL) {
+ fclose(proxy);
+ return NULL;
+ }
+
+ netid = __netdClientDispatch.netIdForResolv(netid);
+
+ if (fprintf(proxy, "gethostbyaddr %s %d %d %u",
+ addrStr, len, af, netid) < 0) {
+ fclose(proxy);
+ return NULL;
+ }
+
+ if (fputc(0, proxy) == EOF || fflush(proxy) != 0) {
+ fclose(proxy);
+ return NULL;
+ }
+
+ struct hostent *result = android_read_hostent(proxy, hp, hbuf, hbuflen, he);
+ fclose(proxy);
+ return result;
+}
+
+struct hostent*
+netbsd_gethostent_r(FILE *hf, struct hostent *hent, char *buf, size_t buflen, int *he)
+{
+ char *p, *name;
+ char *cp, **q;
+ int af, len;
+ size_t anum;
+ char **aliases;
+ size_t maxaliases;
+ struct in6_addr host_addr;
+
+ if (hf == NULL) {
+ *he = NETDB_INTERNAL;
+ errno = EINVAL;
+ return NULL;
+ }
+ p = NULL;
+ setup(aliases, maxaliases);
+
+ /* Allocate a new space to read file lines like upstream does.
+ * To keep reentrancy we cannot use __res_get_static()->hostbuf here,
+ * as the buffer may be used to store content for a previous hostent
+ * returned by non-reentrant functions like gethostbyname().
+ */
+ const size_t line_buf_size = sizeof(__res_get_static()->hostbuf);
+ if ((p = malloc(line_buf_size)) == NULL) {
+ goto nospc;
+ }
+ for (;;) {
+ if (!fgets(p, line_buf_size, hf)) {
+ free(p);
+ free(aliases);
+ *he = HOST_NOT_FOUND;
+ return NULL;
+ }
+ if (*p == '#') {
+ continue;
+ }
+ if (!(cp = strpbrk(p, "#\n"))) {
+ continue;
+ }
+ *cp = '\0';
+ if (!(cp = strpbrk(p, " \t")))
+ continue;
+ *cp++ = '\0';
+ if (inet_pton(AF_INET6, p, &host_addr) > 0) {
+ af = AF_INET6;
+ len = NS_IN6ADDRSZ;
+ } else {
+ if (inet_pton(AF_INET, p, &host_addr) <= 0)
+ continue;
+
+ res_state res = __res_get_state();
+ if (res == NULL)
+ goto nospc;
+ if (res->options & RES_USE_INET6) {
+ map_v4v6_address(buf, buf);
+ af = AF_INET6;
+ len = NS_IN6ADDRSZ;
+ } else {
+ af = AF_INET;
+ len = NS_INADDRSZ;
+ }
+ __res_put_state(res);
+ }
+
+ /* if this is not something we're looking for, skip it. */
+ if (hent->h_addrtype != 0 && hent->h_addrtype != af)
+ continue;
+ if (hent->h_length != 0 && hent->h_length != len)
+ continue;
+
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if ((cp = strpbrk(name = cp, " \t")) != NULL)
+ *cp++ = '\0';
+ q = aliases;
+ while (cp && *cp) {
+ if (*cp == ' ' || *cp == '\t') {
+ cp++;
+ continue;
+ }
+ addalias(q, cp, aliases, maxaliases);
+ if ((cp = strpbrk(cp, " \t")) != NULL)
+ *cp++ = '\0';
+ }
+ break;
+ }
+ hent->h_length = len;
+ hent->h_addrtype = af;
+ HENT_ARRAY(hent->h_addr_list, 1, buf, buflen);
+ anum = (size_t)(q - aliases);
+ HENT_ARRAY(hent->h_aliases, anum, buf, buflen);
+ HENT_COPY(hent->h_addr_list[0], &host_addr, hent->h_length, buf,
+ buflen);
+ hent->h_addr_list[1] = NULL;
+
+ HENT_SCOPY(hent->h_name, name, buf, buflen);
+ for (size_t i = 0; i < anum; i++)
+ HENT_SCOPY(hent->h_aliases[i], aliases[i], buf, buflen);
+ hent->h_aliases[anum] = NULL;
+
+ *he = NETDB_SUCCESS;
+ free(p);
+ free(aliases);
+ return hent;
+nospc:
+ free(p);
+ free(aliases);
+ errno = ENOSPC;
+ *he = NETDB_INTERNAL;
+ return NULL;
+}
+
+static void
+map_v4v6_address(const char *src, char *dst)
+{
+ u_char *p = (u_char *)dst;
+ char tmp[NS_INADDRSZ];
+ int i;
+
+ _DIAGASSERT(src != NULL);
+ _DIAGASSERT(dst != NULL);
+
+ /* Stash a temporary copy so our caller can update in place. */
+ (void)memcpy(tmp, src, NS_INADDRSZ);
+ /* Mark this ipv6 addr as a mapped ipv4. */
+ for (i = 0; i < 10; i++)
+ *p++ = 0x00;
+ *p++ = 0xff;
+ *p++ = 0xff;
+ /* Retrieve the saved copy and we're done. */
+ (void)memcpy(p, tmp, NS_INADDRSZ);
+}
+
+static void
+map_v4v6_hostent(struct hostent *hp, char **bpp, char *ep)
+{
+ char **ap;
+
+ _DIAGASSERT(hp != NULL);
+ _DIAGASSERT(bpp != NULL);
+ _DIAGASSERT(ep != NULL);
+
+ if (hp->h_addrtype != AF_INET || hp->h_length != NS_INADDRSZ)
+ return;
+ hp->h_addrtype = AF_INET6;
+ hp->h_length = NS_IN6ADDRSZ;
+ for (ap = hp->h_addr_list; *ap; ap++) {
+ int i = (int)(sizeof(align) -
+ (size_t)((u_long)*bpp % sizeof(align)));
+
+ if (ep - *bpp < (i + NS_IN6ADDRSZ)) {
+ /* Out of memory. Truncate address list here. XXX */
+ *ap = NULL;
+ return;
+ }
+ *bpp += i;
+ map_v4v6_address(*ap, *bpp);
+ *ap = *bpp;
+ *bpp += NS_IN6ADDRSZ;
+ }
+}
+
+static void
+addrsort(char **ap, int num, res_state res)
+{
+ int i, j;
+ char **p;
+ short aval[MAXADDRS];
+ int needsort = 0;
+
+ _DIAGASSERT(ap != NULL);
+
+ p = ap;
+ for (i = 0; i < num; i++, p++) {
+ for (j = 0 ; (unsigned)j < res->nsort; j++)
+ if (res->sort_list[j].addr.s_addr ==
+ (((struct in_addr *)(void *)(*p))->s_addr &
+ res->sort_list[j].mask))
+ break;
+ aval[i] = j;
+ if (needsort == 0 && i > 0 && j < aval[i-1])
+ needsort = i;
+ }
+ if (!needsort)
+ return;
+
+ while (needsort < num) {
+ for (j = needsort - 1; j >= 0; j--) {
+ if (aval[j] > aval[j+1]) {
+ char *hp;
+
+ i = aval[j];
+ aval[j] = aval[j+1];
+ aval[j+1] = i;
+
+ hp = ap[j];
+ ap[j] = ap[j+1];
+ ap[j+1] = hp;
+ } else
+ break;
+ }
+ needsort++;
+ }
+}
+
+/*ARGSUSED*/
+static int
+_dns_gethtbyname(void *rv, void *cb_data, va_list ap)
+{
+ querybuf *buf;
+ int n, type;
+ struct hostent *hp;
+ const char *name;
+ res_state res;
+ struct getnamaddr *info = rv;
+
+ _DIAGASSERT(rv != NULL);
+
+ name = va_arg(ap, char *);
+ /* NOSTRICT skip string len */(void)va_arg(ap, int);
+ info->hp->h_addrtype = va_arg(ap, int);
+
+ switch (info->hp->h_addrtype) {
+ case AF_INET:
+ info->hp->h_length = NS_INADDRSZ;
+ type = T_A;
+ break;
+ case AF_INET6:
+ info->hp->h_length = NS_IN6ADDRSZ;
+ type = T_AAAA;
+ break;
+ default:
+ return NS_UNAVAIL;
+ }
+ buf = malloc(sizeof(*buf));
+ if (buf == NULL) {
+ *info->he = NETDB_INTERNAL;
+ return NS_NOTFOUND;
+ }
+ res = __res_get_state();
+ if (res == NULL) {
+ free(buf);
+ return NS_NOTFOUND;
+ }
+ n = res_nsearch(res, name, C_IN, type, buf->buf, (int)sizeof(buf->buf));
+ if (n < 0) {
+ free(buf);
+ debugprintf("res_nsearch failed (%d)\n", res, n);
+ __res_put_state(res);
+ return NS_NOTFOUND;
+ }
+ hp = getanswer(buf, n, name, type, res, info->hp, info->buf,
+ info->buflen, info->he);
+ free(buf);
+ __res_put_state(res);
+ if (hp == NULL)
+ switch (*info->he) {
+ case HOST_NOT_FOUND:
+ return NS_NOTFOUND;
+ case TRY_AGAIN:
+ return NS_TRYAGAIN;
+ default:
+ return NS_UNAVAIL;
+ }
+ return NS_SUCCESS;
+}
+
+/*ARGSUSED*/
+static int
+_dns_gethtbyaddr(void *rv, void *cb_data, va_list ap)
+{
+ char qbuf[MAXDNAME + 1], *qp, *ep;
+ int n;
+ querybuf *buf;
+ struct hostent *hp;
+ const unsigned char *uaddr;
+ int advance;
+ res_state res;
+ char *bf;
+ size_t blen;
+ struct getnamaddr *info = rv;
+ unsigned netid, mark;
+
+ _DIAGASSERT(rv != NULL);
+
+ uaddr = va_arg(ap, unsigned char *);
+ info->hp->h_length = va_arg(ap, int);
+ info->hp->h_addrtype = va_arg(ap, int);
+ netid = va_arg(ap, unsigned);
+ mark = va_arg(ap, unsigned);
+
+ switch (info->hp->h_addrtype) {
+ case AF_INET:
+ (void)snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u.in-addr.arpa",
+ (uaddr[3] & 0xff), (uaddr[2] & 0xff),
+ (uaddr[1] & 0xff), (uaddr[0] & 0xff));
+ break;
+
+ case AF_INET6:
+ qp = qbuf;
+ ep = qbuf + sizeof(qbuf) - 1;
+ for (n = NS_IN6ADDRSZ - 1; n >= 0; n--) {
+ advance = snprintf(qp, (size_t)(ep - qp), "%x.%x.",
+ uaddr[n] & 0xf,
+ ((unsigned int)uaddr[n] >> 4) & 0xf);
+ if (advance > 0 && qp + advance < ep)
+ qp += advance;
+ else {
+ *info->he = NETDB_INTERNAL;
+ return NS_NOTFOUND;
+ }
+ }
+ if (strlcat(qbuf, "ip6.arpa", sizeof(qbuf)) >= sizeof(qbuf)) {
+ *info->he = NETDB_INTERNAL;
+ return NS_NOTFOUND;
+ }
+ break;
+ default:
+ return NS_UNAVAIL;
+ }
+
+ buf = malloc(sizeof(*buf));
+ if (buf == NULL) {
+ *info->he = NETDB_INTERNAL;
+ return NS_NOTFOUND;
+ }
+ res = __res_get_state();
+ if (res == NULL) {
+ free(buf);
+ return NS_NOTFOUND;
+ }
+ res_setnetid(res, netid);
+ res_setmark(res, mark);
+ n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, (int)sizeof(buf->buf));
+ if (n < 0) {
+ free(buf);
+ debugprintf("res_nquery failed (%d)\n", res, n);
+ __res_put_state(res);
+ return NS_NOTFOUND;
+ }
+ hp = getanswer(buf, n, qbuf, T_PTR, res, info->hp, info->buf,
+ info->buflen, info->he);
+ free(buf);
+ if (hp == NULL) {
+ __res_put_state(res);
+ switch (*info->he) {
+ case HOST_NOT_FOUND:
+ return NS_NOTFOUND;
+ case TRY_AGAIN:
+ return NS_TRYAGAIN;
+ default:
+ return NS_UNAVAIL;
+ }
+ }
+
+ bf = (void *)(hp->h_addr_list + 2);
+ blen = (size_t)(bf - info->buf);
+ if (blen + info->hp->h_length > info->buflen)
+ goto nospc;
+ hp->h_addr_list[0] = bf;
+ hp->h_addr_list[1] = NULL;
+ (void)memcpy(bf, uaddr, (size_t)info->hp->h_length);
+ if (info->hp->h_addrtype == AF_INET && (res->options & RES_USE_INET6)) {
+ if (blen + NS_IN6ADDRSZ > info->buflen)
+ goto nospc;
+ map_v4v6_address(bf, bf);
+ hp->h_addrtype = AF_INET6;
+ hp->h_length = NS_IN6ADDRSZ;
+ }
+
+ __res_put_state(res);
+ *info->he = NETDB_SUCCESS;
+ return NS_SUCCESS;
+nospc:
+ errno = ENOSPC;
+ *info->he = NETDB_INTERNAL;
+ return NS_UNAVAIL;
+}
+
+#ifdef YP
+/*ARGSUSED*/
+static struct hostent *
+_yp_hostent(char *line, int af, struct getnamaddr *info)
+{
+ struct in6_addr host_addrs[MAXADDRS];
+ char **aliases;
+ size_t maxaliases;
+ char *p = line;
+ char *cp, **q, *ptr;
+ size_t len, anum, i;
+ int addrok;
+ int more;
+ size_t naddrs;
+ struct hostent *hp = info->hp;
+
+ _DIAGASSERT(line != NULL);
+
+ hp->h_name = NULL;
+ hp->h_addrtype = af;
+ switch (af) {
+ case AF_INET:
+ hp->h_length = NS_INADDRSZ;
+ break;
+ case AF_INET6:
+ hp->h_length = NS_IN6ADDRSZ;
+ break;
+ default:
+ return NULL;
+ }
+ setup(aliases, maxaliases);
+ naddrs = 0;
+ q = aliases;
+
+nextline:
+ /* check for host_addrs overflow */
+ if (naddrs >= __arraycount(host_addrs))
+ goto done;
+
+ more = 0;
+ cp = strpbrk(p, " \t");
+ if (cp == NULL)
+ goto done;
+ *cp++ = '\0';
+
+ /* p has should have an address */
+ addrok = inet_pton(af, p, &host_addrs[naddrs]);
+ if (addrok != 1) {
+ /* skip to the next line */
+ while (cp && *cp) {
+ if (*cp == '\n') {
+ cp++;
+ goto nextline;
+ }
+ cp++;
+ }
+ goto done;
+ }
+ naddrs++;
+
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ p = cp;
+ cp = strpbrk(p, " \t\n");
+ if (cp != NULL) {
+ if (*cp == '\n')
+ more = 1;
+ *cp++ = '\0';
+ }
+ if (!hp->h_name)
+ hp->h_name = p;
+ else if (strcmp(hp->h_name, p) == 0)
+ ;
+ else
+ addalias(q, p, aliases, maxaliases);
+ p = cp;
+ if (more)
+ goto nextline;
+
+ while (cp && *cp) {
+ if (*cp == ' ' || *cp == '\t') {
+ cp++;
+ continue;
+ }
+ if (*cp == '\n') {
+ cp++;
+ goto nextline;
+ }
+ addalias(q, cp, aliases, maxaliases);
+ cp = strpbrk(cp, " \t");
+ if (cp != NULL)
+ *cp++ = '\0';
+ }
+
+done:
+ if (hp->h_name == NULL) {
+ free(aliases);
+ return NULL;
+ }
+
+ ptr = info->buf;
+ len = info->buflen;
+
+ anum = (size_t)(q - aliases);
+ HENT_ARRAY(hp->h_addr_list, naddrs, ptr, len);
+ HENT_ARRAY(hp->h_aliases, anum, ptr, len);
+
+ for (i = 0; i < naddrs; i++)
+ HENT_COPY(hp->h_addr_list[i], &host_addrs[i], hp->h_length,
+ ptr, len);
+ hp->h_addr_list[naddrs] = NULL;
+
+ HENT_SCOPY(hp->h_name, hp->h_name, ptr, len);
+
+ for (i = 0; i < anum; i++)
+ HENT_SCOPY(hp->h_aliases[i], aliases[i], ptr, len);
+ hp->h_aliases[anum] = NULL;
+ free(aliases);
+
+ return hp;
+nospc:
+ free(aliases);
+ *info->he = NETDB_INTERNAL;
+ errno = ENOSPC;
+ return NULL;
+}
+
+/*ARGSUSED*/
+int
+_yp_gethtbyaddr(void *rv, void *cb_data, va_list ap)
+{
+ struct hostent *hp = NULL;
+ char *ypcurrent;
+ int ypcurrentlen, r;
+ char name[INET6_ADDRSTRLEN]; /* XXX enough? */
+ const unsigned char *uaddr;
+ int af;
+ const char *map;
+ struct getnamaddr *info = rv;
+
+ _DIAGASSERT(rv != NULL);
+
+ uaddr = va_arg(ap, unsigned char *);
+ /* NOSTRICT skip len */(void)va_arg(ap, int);
+ af = va_arg(ap, int);
+
+ if (!__ypdomain) {
+ if (_yp_check(&__ypdomain) == 0)
+ return NS_UNAVAIL;
+ }
+ /*
+ * XXX unfortunately, we cannot support IPv6 extended scoped address
+ * notation here. gethostbyaddr() is not scope-aware. too bad.
+ */
+ if (inet_ntop(af, uaddr, name, (socklen_t)sizeof(name)) == NULL)
+ return NS_UNAVAIL;
+ switch (af) {
+ case AF_INET:
+ map = "hosts.byaddr";
+ break;
+ default:
+ map = "ipnodes.byaddr";
+ break;
+ }
+ ypcurrent = NULL;
+ r = yp_match(__ypdomain, map, name,
+ (int)strlen(name), &ypcurrent, &ypcurrentlen);
+ if (r == 0)
+ hp = _yp_hostent(ypcurrent, af, info);
+ else
+ hp = NULL;
+ free(ypcurrent);
+ if (hp == NULL) {
+ *info->he = HOST_NOT_FOUND;
+ return NS_NOTFOUND;
+ }
+ return NS_SUCCESS;
+}
+
+/*ARGSUSED*/
+int
+_yp_gethtbyname(void *rv, void *cb_data, va_list ap)
+{
+ struct hostent *hp;
+ char *ypcurrent;
+ int ypcurrentlen, r;
+ const char *name;
+ int af;
+ const char *map;
+ struct getnamaddr *info = rv;
+
+ _DIAGASSERT(rv != NULL);
+
+ name = va_arg(ap, char *);
+ /* NOSTRICT skip string len */(void)va_arg(ap, int);
+ af = va_arg(ap, int);
+
+ if (!__ypdomain) {
+ if (_yp_check(&__ypdomain) == 0)
+ return NS_UNAVAIL;
+ }
+ switch (af) {
+ case AF_INET:
+ map = "hosts.byname";
+ break;
+ default:
+ map = "ipnodes.byname";
+ break;
+ }
+ ypcurrent = NULL;
+ r = yp_match(__ypdomain, map, name,
+ (int)strlen(name), &ypcurrent, &ypcurrentlen);
+ if (r == 0)
+ hp = _yp_hostent(ypcurrent, af, info);
+ else
+ hp = NULL;
+ free(ypcurrent);
+ if (hp == NULL) {
+ *info->he = HOST_NOT_FOUND;
+ return NS_NOTFOUND;
+ }
+ return NS_SUCCESS;
+}
+#endif
+
+/*
+ * Non-reentrant versions.
+ */
+
+struct hostent *
+gethostbyname(const char *name)
+{
+ struct hostent *result = NULL;
+ res_static rs = __res_get_static(); /* Use res_static to provide thread-safety. */
+
+ gethostbyname_r(name, &rs->host, rs->hostbuf, sizeof(rs->hostbuf), &result, &h_errno);
+ return result;
+}
+
+struct hostent *
+gethostbyname2(const char *name, int af)
+{
+ struct hostent *result = NULL;
+ res_static rs = __res_get_static(); /* Use res_static to provide thread-safety. */
+
+ gethostbyname2_r(name, af, &rs->host, rs->hostbuf, sizeof(rs->hostbuf), &result, &h_errno);
+ return result;
+}
+
+struct hostent *
+android_gethostbynamefornet(const char *name, int af, unsigned netid, unsigned mark)
+{
+ struct hostent *hp;
+ res_state res = __res_get_state();
+ if (res == NULL)
+ return NULL;
+ res_static rs = __res_get_static(); /* Use res_static to provide thread-safety. */
+ hp = gethostbyname_internal(name, af, res, &rs->host, rs->hostbuf, sizeof(rs->hostbuf),
+ &h_errno, netid, mark);
+ __res_put_state(res);
+ return hp;
+}
+
+struct hostent *
+gethostbyaddr(const void *addr, socklen_t len, int af)
+{
+ return android_gethostbyaddrfornet_proxy(addr, len, af, NETID_UNSET, MARK_UNSET);
+}
+
+struct hostent *
+android_gethostbyaddrfornet(const void *addr, socklen_t len, int af, unsigned netid, unsigned mark)
+{
+ return android_gethostbyaddrfornet_proxy(addr, len, af, netid, mark);
+}
+
+__LIBC_HIDDEN__ struct hostent*
+android_gethostbyaddrfornet_proxy(const void* addr, socklen_t len, int af,
+ unsigned netid, unsigned mark)
+{
+ res_static rs = __res_get_static(); /* Use res_static to provide thread-safety. */
+ return android_gethostbyaddrfornet_proxy_internal(addr, len, af, &rs->host, rs->hostbuf,
+ sizeof(rs->hostbuf), &h_errno, netid, mark);
+}
+
+struct hostent *
+gethostent(void)
+{
+ res_static rs = __res_get_static();
+ if (!rs->hostf) {
+ sethostent_r(&rs->hostf);
+ if (!rs->hostf) {
+ h_errno = NETDB_INTERNAL;
+ return NULL;
+ }
+ }
+ memset(&rs->host, 0, sizeof(rs->host));
+ return netbsd_gethostent_r(rs->hostf, &rs->host, rs->hostbuf, sizeof(rs->hostbuf), &h_errno);
+}
diff --git a/libc/dns/net/nsdispatch.c b/libc/dns/net/nsdispatch.c
index fb6d8f6..d025592 100644
--- a/libc/dns/net/nsdispatch.c
+++ b/libc/dns/net/nsdispatch.c
@@ -71,6 +71,7 @@
#include <sys/cdefs.h>
#include <assert.h>
+#include <errno.h>
#include <nsswitch.h>
#include <stdarg.h>
#include <strings.h>
@@ -133,6 +134,10 @@
continue;
if (result & srclist[i].flags)
break;
+ /* Stop trying next resolver when there is a memory space fatal error. */
+ if ((result & NS_UNAVAIL) != 0 && errno == ENOSPC) {
+ break;
+ }
}
}
result &= NS_STATUSMASK; /* clear private flags in result */
diff --git a/libc/dns/net/sethostent.c b/libc/dns/net/sethostent.c
new file mode 100644
index 0000000..916421e
--- /dev/null
+++ b/libc/dns/net/sethostent.c
@@ -0,0 +1,275 @@
+/* $NetBSD: sethostent.c,v 1.20 2014/03/17 13:24:23 christos Exp $ */
+
+/*
+ * Copyright (c) 1985, 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. 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.
+ */
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)sethostent.c 8.1 (Berkeley) 6/4/93";
+static char rcsid[] = "Id: sethostent.c,v 8.5 1996/09/28 06:51:07 vixie Exp ";
+#else
+__RCSID("$NetBSD: sethostent.c,v 1.20 2014/03/17 13:24:23 christos Exp $");
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <assert.h>
+#include <string.h>
+#include <nsswitch.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "hostent.h"
+#include "resolv_private.h"
+
+#define ALIGNBYTES (sizeof(uintptr_t) - 1)
+#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)
+
+#ifndef _REENTRANT
+void res_close(void);
+#endif
+
+static struct hostent *_hf_gethtbyname2(const char *, int, struct getnamaddr *);
+
+static const char *_h_hosts = _PATH_HOSTS;
+
+void
+sethostent_r(FILE **hf)
+{
+ if (!*hf)
+ *hf = fopen(_h_hosts, "re");
+ else
+ rewind(*hf);
+}
+
+void
+endhostent_r(FILE **hf)
+{
+ if (*hf) {
+ (void)fclose(*hf);
+ *hf = NULL;
+ }
+}
+
+/*ARGSUSED*/
+int
+_hf_gethtbyname(void *rv, void *cb_data, va_list ap)
+{
+ struct hostent *hp;
+ const char *name;
+ int af;
+ struct getnamaddr *info = rv;
+
+ _DIAGASSERT(rv != NULL);
+
+ name = va_arg(ap, char *);
+ /* NOSTRICT skip string len */(void)va_arg(ap, int);
+ af = va_arg(ap, int);
+
+#if 0
+ {
+ res_state res = __res_get_state();
+ if (res == NULL)
+ return NS_NOTFOUND;
+ if (res->options & RES_USE_INET6)
+ hp = _hf_gethtbyname2(name, AF_INET6, info);
+ else
+ hp = NULL;
+ if (hp == NULL)
+ hp = _hf_gethtbyname2(name, AF_INET, info);
+ __res_put_state(res);
+ }
+#else
+ hp = _hf_gethtbyname2(name, af, info);
+#endif
+ if (hp == NULL) {
+ if (*info->he == NETDB_INTERNAL && errno == ENOSPC) {
+ return NS_UNAVAIL;
+ }
+ return NS_NOTFOUND;
+ }
+ return NS_SUCCESS;
+}
+
+static struct hostent *
+_hf_gethtbyname2(const char *name, int af, struct getnamaddr *info)
+{
+ struct hostent *hp, hent;
+ char *buf, *ptr;
+ size_t len, anum, num, i;
+ FILE *hf;
+ char *aliases[MAXALIASES];
+ char *addr_ptrs[MAXADDRS];
+
+ _DIAGASSERT(name != NULL);
+
+ hf = NULL;
+ sethostent_r(&hf);
+ if (hf == NULL) {
+ errno = EINVAL;
+ *info->he = NETDB_INTERNAL;
+ return NULL;
+ }
+
+ if ((ptr = buf = malloc(len = info->buflen)) == NULL) {
+ endhostent_r(&hf);
+ *info->he = NETDB_INTERNAL;
+ return NULL;
+ }
+
+ anum = 0; /* XXX: gcc */
+ hent.h_name = NULL; /* XXX: gcc */
+ hent.h_addrtype = 0; /* XXX: gcc */
+ hent.h_length = 0; /* XXX: gcc */
+
+ for (num = 0; num < MAXADDRS;) {
+ info->hp->h_addrtype = af;
+ info->hp->h_length = 0;
+
+ hp = netbsd_gethostent_r(hf, info->hp, info->buf, info->buflen,
+ info->he);
+ if (hp == NULL) {
+ if (*info->he == NETDB_INTERNAL && errno == ENOSPC) {
+ goto nospc;
+ }
+ break;
+ }
+
+ if (strcasecmp(hp->h_name, name) != 0) {
+ char **cp;
+ for (cp = hp->h_aliases; *cp != NULL; cp++)
+ if (strcasecmp(*cp, name) == 0)
+ break;
+ if (*cp == NULL) continue;
+ }
+
+ if (num == 0) {
+ hent.h_addrtype = af = hp->h_addrtype;
+ hent.h_length = hp->h_length;
+
+ HENT_SCOPY(hent.h_name, hp->h_name, ptr, len);
+ for (anum = 0; hp->h_aliases[anum]; anum++) {
+ if (anum >= MAXALIASES)
+ goto nospc;
+ HENT_SCOPY(aliases[anum], hp->h_aliases[anum],
+ ptr, len);
+ }
+ ptr = (void *)ALIGN(ptr);
+ if ((size_t)(ptr - buf) >= info->buflen)
+ goto nospc;
+ }
+
+ if (num >= MAXADDRS)
+ goto nospc;
+ HENT_COPY(addr_ptrs[num], hp->h_addr_list[0], hp->h_length, ptr,
+ len);
+ num++;
+ }
+ endhostent_r(&hf);
+
+ if (num == 0) {
+ *info->he = HOST_NOT_FOUND;
+ free(buf);
+ return NULL;
+ }
+
+ hp = info->hp;
+ ptr = info->buf;
+ len = info->buflen;
+
+ hp->h_addrtype = hent.h_addrtype;
+ hp->h_length = hent.h_length;
+
+ HENT_ARRAY(hp->h_aliases, anum, ptr, len);
+ HENT_ARRAY(hp->h_addr_list, num, ptr, len);
+
+ for (i = 0; i < num; i++)
+ HENT_COPY(hp->h_addr_list[i], addr_ptrs[i], hp->h_length, ptr,
+ len);
+ hp->h_addr_list[num] = NULL;
+
+ HENT_SCOPY(hp->h_name, hent.h_name, ptr, len);
+
+ for (i = 0; i < anum; i++)
+ HENT_SCOPY(hp->h_aliases[i], aliases[i], ptr, len);
+ hp->h_aliases[anum] = NULL;
+
+ free(buf);
+ return hp;
+nospc:
+ endhostent_r(&hf);
+ *info->he = NETDB_INTERNAL;
+ free(buf);
+ errno = ENOSPC;
+ return NULL;
+}
+
+/*ARGSUSED*/
+int
+_hf_gethtbyaddr(void *rv, void *cb_data, va_list ap)
+{
+ struct hostent *hp;
+ const unsigned char *addr;
+ struct getnamaddr *info = rv;
+ FILE *hf;
+
+ _DIAGASSERT(rv != NULL);
+
+ addr = va_arg(ap, unsigned char *);
+ info->hp->h_length = va_arg(ap, int);
+ info->hp->h_addrtype = va_arg(ap, int);
+
+ hf = NULL;
+ sethostent_r(&hf);
+ if (hf == NULL) {
+ *info->he = NETDB_INTERNAL;
+ return NS_UNAVAIL;
+ }
+ while ((hp = netbsd_gethostent_r(hf, info->hp, info->buf, info->buflen,
+ info->he)) != NULL)
+ if (!memcmp(hp->h_addr_list[0], addr, (size_t)hp->h_length))
+ break;
+ endhostent_r(&hf);
+
+ if (hp == NULL) {
+ if (errno == ENOSPC) {
+ return NS_UNAVAIL;
+ }
+ *info->he = HOST_NOT_FOUND;
+ return NS_NOTFOUND;
+ }
+ return NS_SUCCESS;
+}
diff --git a/libc/include/netdb.h b/libc/include/netdb.h
index 527d5c1..e165376 100644
--- a/libc/include/netdb.h
+++ b/libc/include/netdb.h
@@ -209,7 +209,7 @@
void endservent(void);
void freehostent(struct hostent *);
struct hostent *gethostbyaddr(const void *, socklen_t, int);
-int gethostbyaddr_r(const void *, int, int, struct hostent *, char *, size_t, struct hostent **, int *);
+int gethostbyaddr_r(const void *, socklen_t, int, struct hostent *, char *, size_t, struct hostent **, int *);
struct hostent *gethostbyname(const char *);
int gethostbyname_r(const char *, struct hostent *, char *, size_t, struct hostent **, int *);
struct hostent *gethostbyname2(const char *, int);
diff --git a/libc/include/sys/stat.h b/libc/include/sys/stat.h
index e3f41a9..7017865 100644
--- a/libc/include/sys/stat.h
+++ b/libc/include/sys/stat.h
@@ -29,7 +29,6 @@
#ifndef _SYS_STAT_H_
#define _SYS_STAT_H_
-#include <endian.h>
#include <linux/stat.h>
#include <machine/timespec.h>
#include <sys/cdefs.h>
@@ -39,15 +38,15 @@
#if defined(__aarch64__)
#define __STAT64_BODY \
- unsigned long st_dev; \
- unsigned long st_ino; \
- unsigned int st_mode; \
- unsigned int st_nlink; \
+ dev_t st_dev; \
+ ino_t st_ino; \
+ mode_t st_mode; \
+ nlink_t st_nlink; \
uid_t st_uid; \
gid_t st_gid; \
- unsigned long st_rdev; \
+ dev_t st_rdev; \
unsigned long __pad1; \
- long st_size; \
+ off_t st_size; \
int st_blksize; \
int __pad2; \
long st_blocks; \
@@ -57,13 +56,13 @@
unsigned int __unused4; \
unsigned int __unused5; \
-#elif defined(__mips__)
+#elif defined(__mips__) /* and mips64 */
#define __STAT64_BODY \
unsigned int st_dev; \
unsigned int __pad0[3]; \
unsigned long long st_ino; \
- unsigned int st_mode; \
- unsigned int st_nlink; \
+ mode_t st_mode; \
+ nlink_t st_nlink; \
uid_t st_uid; \
gid_t st_gid; \
unsigned int st_rdev; \
@@ -78,15 +77,15 @@
#elif defined(__x86_64__)
#define __STAT64_BODY \
- unsigned long st_dev; \
- unsigned long st_ino; \
+ dev_t st_dev; \
+ ino_t st_ino; \
unsigned long st_nlink; \
- unsigned int st_mode; \
+ mode_t st_mode; \
uid_t st_uid; \
gid_t st_gid; \
unsigned int __pad0; \
- unsigned long st_rdev; \
- long st_size; \
+ dev_t st_rdev; \
+ off_t st_size; \
long st_blksize; \
long st_blocks; \
struct timespec st_atim; \
@@ -94,13 +93,13 @@
struct timespec st_ctim; \
long __pad3[3]; \
-#else
+#else /* __arm__ || __i386__ */
#define __STAT64_BODY \
unsigned long long st_dev; \
unsigned char __pad0[4]; \
unsigned long __st_ino; \
unsigned int st_mode; \
- unsigned int st_nlink; \
+ nlink_t st_nlink; \
uid_t st_uid; \
gid_t st_gid; \
unsigned long long st_rdev; \
diff --git a/libc/private/bionic_tls.h b/libc/private/bionic_tls.h
index 4a35166..944f957 100644
--- a/libc/private/bionic_tls.h
+++ b/libc/private/bionic_tls.h
@@ -85,7 +85,8 @@
* ttyname libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
* strerror libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
* strsignal libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
- * stubs libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
+ * passwd libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
+ * group libc (GLOBAL_INIT_THREAD_LOCAL_BUFFER)
* _res_key libc
* je_thread_allocated_tsd jemalloc
* je_arenas_tsd jemalloc
@@ -95,7 +96,7 @@
*
*/
-#define LIBC_TLS_RESERVED_SLOTS 11
+#define LIBC_TLS_RESERVED_SLOTS 12
#if defined(USE_JEMALLOC)
/* jemalloc uses 5 keys for itself. */
diff --git a/libc/tools/generate-NOTICE.py b/libc/tools/generate-NOTICE.py
index 3edc299..79b4ea9 100755
--- a/libc/tools/generate-NOTICE.py
+++ b/libc/tools/generate-NOTICE.py
@@ -1,7 +1,7 @@
#!/usr/bin/python
# Run with directory arguments from any directory, with no special setup required.
# Or:
-# for i in libc libdl libm linker libstdc++ libthread_db ; do ./libc/tools/generate-NOTICE.py $i > $i/NOTICE ; done
+# for i in libc libdl libm linker libstdc++ ; do ./libc/tools/generate-NOTICE.py $i > $i/NOTICE ; done
import ftplib
import hashlib
diff --git a/libdl/Android.mk b/libdl/Android.mk
index c9fca0e..2a0724a 100644
--- a/libdl/Android.mk
+++ b/libdl/Android.mk
@@ -36,6 +36,7 @@
LOCAL_ALLOW_UNDEFINED_SYMBOLS := true
LOCAL_SYSTEM_SHARED_LIBRARIES :=
+LOCAL_ADDRESS_SANITIZER := false
include $(BUILD_SHARED_LIBRARY)
# A dummy libdl.a. Need for static executables using the LLVM unwinder. Most
@@ -48,4 +49,5 @@
LOCAL_MODULE := libdl
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_ADDRESS_SANITIZER := false
include $(BUILD_STATIC_LIBRARY)
diff --git a/libm/Android.mk b/libm/Android.mk
index d4cd7c3..cc2b8be 100644
--- a/libm/Android.mk
+++ b/libm/Android.mk
@@ -285,6 +285,7 @@
LOCAL_SYSTEM_SHARED_LIBRARIES := libc
LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
+LOCAL_ADDRESS_SANITIZER := false
# arch-specific settings
LOCAL_C_INCLUDES_arm := $(LOCAL_PATH)/arm
@@ -321,6 +322,7 @@
LOCAL_WHOLE_STATIC_LIBRARIES := libm
LOCAL_NATIVE_COVERAGE := $(bionic_coverage)
+LOCAL_ADDRESS_SANITIZER := false
LOCAL_CXX_STL := none
diff --git a/libm/NOTICE b/libm/NOTICE
index 5be60db..70f2f46 100644
--- a/libm/NOTICE
+++ b/libm/NOTICE
@@ -549,32 +549,6 @@
-------------------------------------------------------------------
-Copyright (c) 2004-2011 David Schultz <das@FreeBSD.ORG>
-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.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
-
--------------------------------------------------------------------
-
Copyright (c) 2005 Bruce D. Evans and Steven G. Kargl
All rights reserved.
@@ -976,6 +950,32 @@
-------------------------------------------------------------------
+Copyright (c) 2012 Stephen Montgomery-Smith <stephen@FreeBSD.ORG>
+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.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+
+-------------------------------------------------------------------
+
Copyright (c) 2013 David Chisnall
All rights reserved.
diff --git a/linker/Android.mk b/linker/Android.mk
index d6e0095..0383e7b 100644
--- a/linker/Android.mk
+++ b/linker/Android.mk
@@ -19,6 +19,13 @@
LOCAL_SRC_FILES_mips := arch/mips/begin.S
LOCAL_SRC_FILES_mips64 := arch/mips64/begin.S
+# GNU assembler aborted with clang's output for linker.cpp:
+# Assertion failure in get_line_subseg at
+# /s/ndk-toolchain/src/build/../binutils/binutils-2.24/gas/dwarf2dbg.c line 271.
+ifeq ($(TARGET_ARCH),mips)
+ LOCAL_CLANG_CFLAGS += -integrated-as
+endif
+
LOCAL_LDFLAGS := \
-shared \
-Wl,-Bsymbolic \
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 3409931..babefeb 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -2402,6 +2402,13 @@
*dp = &_r_debug;
}
break;
+ case DT_MIPS_RLD_MAP2:
+ // Set the DT_MIPS_RLD_MAP2 entry to the address of _r_debug for GDB.
+ {
+ r_debug** dp = reinterpret_cast<r_debug**>(reinterpret_cast<ElfW(Addr)>(d) + d->d_un.d_val);
+ *dp = &_r_debug;
+ }
+ break;
case DT_MIPS_RLD_VERSION:
case DT_MIPS_FLAGS:
diff --git a/tests/netdb_test.cpp b/tests/netdb_test.cpp
index 0cebe4e..ab5b487 100644
--- a/tests/netdb_test.cpp
+++ b/tests/netdb_test.cpp
@@ -14,11 +14,13 @@
* limitations under the License.
*/
+#include <netdb.h>
+
#include <gtest/gtest.h>
+#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
-#include <netdb.h>
#include <netinet/in.h>
TEST(netdb, getaddrinfo_NULL_host) {
@@ -114,8 +116,7 @@
ASSERT_EQ(EAI_FAMILY, getnameinfo(sa, too_little, tmp, sizeof(tmp), NULL, 0, NI_NUMERICHOST));
}
-TEST(netdb, gethostbyname) {
- hostent* hent = gethostbyname("localhost");
+void VerifyLocalhost(hostent *hent) {
ASSERT_TRUE(hent != NULL);
ASSERT_EQ(hent->h_addrtype, AF_INET);
ASSERT_EQ(hent->h_addr[0], 127);
@@ -124,6 +125,125 @@
ASSERT_EQ(hent->h_addr[3], 1);
}
+TEST(netdb, gethostbyname) {
+ hostent* hp = gethostbyname("localhost");
+ VerifyLocalhost(hp);
+}
+
+TEST(netdb, gethostbyname2) {
+ hostent* hp = gethostbyname2("localhost", AF_INET);
+ VerifyLocalhost(hp);
+}
+
+TEST(netdb, gethostbyname_r) {
+ hostent hent;
+ hostent *hp;
+ char buf[512];
+ int err;
+ int result = gethostbyname_r("localhost", &hent, buf, sizeof(buf), &hp, &err);
+ ASSERT_EQ(0, result);
+ VerifyLocalhost(hp);
+
+ // Change hp->h_addr to test reentrancy.
+ hp->h_addr[0] = 0;
+
+ hostent hent2;
+ hostent *hp2;
+ char buf2[512];
+ result = gethostbyname_r("localhost", &hent2, buf2, sizeof(buf2), &hp2, &err);
+ ASSERT_EQ(0, result);
+ VerifyLocalhost(hp2);
+
+ ASSERT_EQ(0, hp->h_addr[0]);
+}
+
+TEST(netdb, gethostbyname2_r) {
+ hostent hent;
+ hostent *hp;
+ char buf[512];
+ int err;
+ int result = gethostbyname2_r("localhost", AF_INET, &hent, buf, sizeof(buf), &hp, &err);
+ ASSERT_EQ(0, result);
+ VerifyLocalhost(hp);
+
+ // Change hp->h_addr to test reentrancy.
+ hp->h_addr[0] = 0;
+
+ hostent hent2;
+ hostent *hp2;
+ char buf2[512];
+ result = gethostbyname2_r("localhost", AF_INET, &hent2, buf2, sizeof(buf2), &hp2, &err);
+ ASSERT_EQ(0, result);
+ VerifyLocalhost(hp2);
+
+ ASSERT_EQ(0, hp->h_addr[0]);
+}
+
+TEST(netdb, gethostbyaddr) {
+ char addr[4];
+ ASSERT_EQ(1, inet_pton(AF_INET, "127.0.0.1", addr));
+ hostent *hp = gethostbyaddr(addr, sizeof(addr), AF_INET);
+ VerifyLocalhost(hp);
+}
+
+TEST(netdb, gethostbyaddr_r) {
+ char addr[4];
+ ASSERT_EQ(1, inet_pton(AF_INET, "127.0.0.1", addr));
+
+ hostent hent;
+ hostent *hp;
+ char buf[512];
+ int err;
+ int result = gethostbyaddr_r(addr, sizeof(addr), AF_INET, &hent, buf, sizeof(buf), &hp, &err);
+ ASSERT_EQ(0, result);
+ VerifyLocalhost(hp);
+
+ // Change hp->h_addr to test reentrancy.
+ hp->h_addr[0] = 0;
+
+ hostent hent2;
+ hostent *hp2;
+ char buf2[512];
+ result = gethostbyaddr_r(addr, sizeof(addr), AF_INET, &hent2, buf2, sizeof(buf2), &hp2, &err);
+ ASSERT_EQ(0, result);
+ VerifyLocalhost(hp2);
+
+ ASSERT_EQ(0, hp->h_addr[0]);
+}
+
+TEST(netdb, gethostbyname_r_ERANGE) {
+ hostent hent;
+ hostent *hp;
+ char buf[4]; // Use too small buffer.
+ int err;
+ int result = gethostbyname_r("localhost", &hent, buf, sizeof(buf), &hp, &err);
+ ASSERT_EQ(ERANGE, result);
+ ASSERT_EQ(NULL, hp);
+}
+
+TEST(netdb, gethostbyname2_r_ERANGE) {
+ hostent hent;
+ hostent *hp;
+ char buf[4]; // Use too small buffer.
+ int err;
+ int result = gethostbyname2_r("localhost", AF_INET, &hent, buf, sizeof(buf), &hp, &err);
+ ASSERT_EQ(ERANGE, result);
+ ASSERT_EQ(NULL, hp);
+}
+
+TEST(netdb, gethostbyaddr_r_ERANGE) {
+ char addr[4];
+ ASSERT_EQ(1, inet_pton(AF_INET, "127.0.0.1", addr));
+
+ hostent hent;
+ hostent *hp;
+ char buf[4]; // Use too small buffer.
+ int err;
+ int result = gethostbyaddr_r(addr, sizeof(addr), AF_INET, &hent, buf, sizeof(buf), &hp, &err);
+ ASSERT_EQ(ERANGE, result);
+ ASSERT_EQ(NULL, hp);
+}
+
TEST(netdb, getservbyname) {
// smtp is TCP-only, so we know we'll get 25/tcp back.
servent* s = getservbyname("smtp", NULL);