| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright (C) 2008 The Android Open Source Project | 
|  | 3 | * All rights reserved. | 
|  | 4 | * | 
|  | 5 | * Redistribution and use in source and binary forms, with or without | 
|  | 6 | * modification, are permitted provided that the following conditions | 
|  | 7 | * are met: | 
|  | 8 | *  * Redistributions of source code must retain the above copyright | 
|  | 9 | *    notice, this list of conditions and the following disclaimer. | 
|  | 10 | *  * Redistributions in binary form must reproduce the above copyright | 
|  | 11 | *    notice, this list of conditions and the following disclaimer in | 
|  | 12 | *    the documentation and/or other materials provided with the | 
|  | 13 | *    distribution. | 
|  | 14 | * | 
|  | 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
|  | 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
|  | 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | 
|  | 18 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | 
|  | 19 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | 
|  | 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | 
|  | 21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS | 
|  | 22 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | 
|  | 23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | 
|  | 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | 
|  | 25 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 
|  | 26 | * SUCH DAMAGE. | 
|  | 27 | */ | 
|  | 28 | #include <sys/cdefs.h> | 
|  | 29 | #include <sys/types.h> | 
|  | 30 | #include <arpa/inet.h> | 
| Calin Juravle | 569fb98 | 2014-03-04 15:01:29 +0000 | [diff] [blame] | 31 | #include <arpa/nameser.h> | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 32 | #include <netdb.h> | 
|  | 33 | #include "resolv_private.h" | 
|  | 34 | #include "resolv_cache.h" | 
|  | 35 | #include <pthread.h> | 
|  | 36 | #include <stdlib.h> | 
| Elliott Hughes | 76f8916 | 2015-01-26 13:34:58 -0800 | [diff] [blame] | 37 | #include <string.h> | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 38 |  | 
|  | 39 | #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ | 
|  | 40 | #include <sys/_system_properties.h> | 
|  | 41 |  | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 42 | /* Set to 1 to enable debug traces */ | 
|  | 43 | #define DEBUG 0 | 
|  | 44 |  | 
|  | 45 | #if DEBUG | 
| Elliott Hughes | eb847bc | 2013-10-09 15:50:50 -0700 | [diff] [blame] | 46 | #  include "private/libc_logging.h" | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 47 | #  include <unistd.h>  /* for gettid() */ | 
| Elliott Hughes | 8f2a5a0 | 2013-03-15 15:30:25 -0700 | [diff] [blame] | 48 | #  define D(...) __libc_format_log(ANDROID_LOG_DEBUG,"libc", __VA_ARGS__) | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 49 | #else | 
|  | 50 | #  define D(...)  do{}while(0) | 
|  | 51 | #endif | 
|  | 52 |  | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 53 | typedef struct { | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 54 | int                  _h_errno; | 
| Szymon Jakubczak | ea9bf67 | 2014-02-14 17:07:23 -0500 | [diff] [blame] | 55 | // TODO: Have one __res_state per network so we don't have to repopulate frequently. | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 56 | struct __res_state  _nres[1]; | 
|  | 57 | unsigned             _serial; | 
|  | 58 | struct prop_info*   _pi; | 
|  | 59 | struct res_static   _rstatic[1]; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 60 | } _res_thread; | 
|  | 61 |  | 
|  | 62 | static _res_thread* | 
|  | 63 | _res_thread_alloc(void) | 
|  | 64 | { | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 65 | _res_thread*  rt = calloc(1, sizeof(*rt)); | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 66 |  | 
|  | 67 | if (rt) { | 
|  | 68 | rt->_h_errno = 0; | 
|  | 69 | /* Special system property which tracks any changes to 'net.*'. */ | 
|  | 70 | rt->_serial = 0; | 
|  | 71 | rt->_pi = (struct prop_info*) __system_property_find("net.change"); | 
|  | 72 | if (rt->_pi) { | 
| Colin Cross | 5cf32de | 2013-01-23 23:07:06 -0800 | [diff] [blame] | 73 | rt->_serial = __system_property_serial(rt->_pi); | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 74 | } | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 75 | memset(rt->_rstatic, 0, sizeof rt->_rstatic); | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 76 | } | 
|  | 77 | return rt; | 
|  | 78 | } | 
|  | 79 |  | 
|  | 80 | static void | 
|  | 81 | _res_static_done( res_static  rs ) | 
|  | 82 | { | 
|  | 83 | /* fortunately, there is nothing to do here, since the | 
|  | 84 | * points in h_addr_ptrs and host_aliases should all | 
|  | 85 | * point to 'hostbuf' | 
|  | 86 | */ | 
|  | 87 | if (rs->hostf) {  /* should not happen in theory, but just be safe */ | 
|  | 88 | fclose(rs->hostf); | 
|  | 89 | rs->hostf = NULL; | 
|  | 90 | } | 
|  | 91 | free(rs->servent.s_aliases); | 
|  | 92 | } | 
|  | 93 |  | 
|  | 94 | static void | 
|  | 95 | _res_thread_free( void*  _rt ) | 
|  | 96 | { | 
|  | 97 | _res_thread*  rt = _rt; | 
|  | 98 |  | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 99 | D("%s: rt=%p for thread=%d", __FUNCTION__, rt, gettid()); | 
|  | 100 |  | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 101 | _res_static_done(rt->_rstatic); | 
|  | 102 | res_ndestroy(rt->_nres); | 
|  | 103 | free(rt); | 
|  | 104 | } | 
|  | 105 |  | 
| Elliott Hughes | 6170693 | 2015-03-31 10:56:58 -0700 | [diff] [blame] | 106 | static pthread_key_t _res_key; | 
|  | 107 |  | 
|  | 108 | __attribute__((constructor)) static void __res_key_init() { | 
|  | 109 | pthread_key_create(&_res_key, _res_thread_free); | 
|  | 110 | } | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 111 |  | 
|  | 112 | static _res_thread* | 
|  | 113 | _res_thread_get(void) | 
|  | 114 | { | 
|  | 115 | _res_thread*  rt; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 116 | rt = pthread_getspecific( _res_key ); | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 117 |  | 
|  | 118 | if (rt != NULL) { | 
|  | 119 | /* We already have one thread-specific DNS state object. | 
|  | 120 | * Check the serial value for any changes to net.* properties */ | 
|  | 121 | D("%s: Called for tid=%d rt=%p rt->pi=%p rt->serial=%d", | 
|  | 122 | __FUNCTION__, gettid(), rt, rt->_pi, rt->_serial); | 
|  | 123 | if (rt->_pi == NULL) { | 
|  | 124 | /* The property wasn't created when _res_thread_get() was | 
|  | 125 | * called the last time. This should only happen very | 
|  | 126 | * early during the boot sequence. First, let's try to see if it | 
|  | 127 | * is here now. */ | 
|  | 128 | rt->_pi = (struct prop_info*) __system_property_find("net.change"); | 
|  | 129 | if (rt->_pi == NULL) { | 
|  | 130 | /* Still nothing, return current state */ | 
| Pierre Imai | fff3567 | 2016-04-18 11:42:14 +0900 | [diff] [blame] | 131 | D("%s: exiting for tid=%d rt=%p since system property not found", | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 132 | __FUNCTION__, gettid(), rt); | 
|  | 133 | return rt; | 
|  | 134 | } | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 135 | } | 
| Colin Cross | 5cf32de | 2013-01-23 23:07:06 -0800 | [diff] [blame] | 136 | if (rt->_serial == __system_property_serial(rt->_pi)) { | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 137 | /* Nothing changed, so return the current state */ | 
|  | 138 | D("%s: tid=%d rt=%p nothing changed, returning", | 
|  | 139 | __FUNCTION__, gettid(), rt); | 
|  | 140 | return rt; | 
|  | 141 | } | 
|  | 142 | /* Update the recorded serial number, and go reset the state */ | 
| Colin Cross | 5cf32de | 2013-01-23 23:07:06 -0800 | [diff] [blame] | 143 | rt->_serial = __system_property_serial(rt->_pi); | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 144 | goto RESET_STATE; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 145 | } | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 146 |  | 
|  | 147 | /* It is the first time this function is called in this thread, | 
|  | 148 | * we need to create a new thread-specific DNS resolver state. */ | 
|  | 149 | rt = _res_thread_alloc(); | 
|  | 150 | if (rt == NULL) { | 
|  | 151 | return NULL; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 152 | } | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 153 | pthread_setspecific( _res_key, rt ); | 
|  | 154 | D("%s: tid=%d Created new DNS state rt=%p", | 
|  | 155 | __FUNCTION__, gettid(), rt); | 
|  | 156 |  | 
|  | 157 | RESET_STATE: | 
|  | 158 | /* Reset the state, note that res_ninit() can now properly reset | 
|  | 159 | * an existing state without leaking memory. | 
|  | 160 | */ | 
|  | 161 | D("%s: tid=%d, rt=%p, resetting DNS state (options RES_INIT=%d)", | 
|  | 162 | __FUNCTION__, gettid(), rt, (rt->_nres->options & RES_INIT) != 0); | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 163 | if ( res_ninit( rt->_nres ) < 0 ) { | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 164 | /* This should not happen */ | 
|  | 165 | D("%s: tid=%d rt=%p, woot, res_ninit() returned < 0", | 
|  | 166 | __FUNCTION__, gettid(), rt); | 
|  | 167 | _res_thread_free(rt); | 
|  | 168 | pthread_setspecific( _res_key, NULL ); | 
|  | 169 | return NULL; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 170 | } | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 171 | return rt; | 
|  | 172 | } | 
|  | 173 |  | 
| Jim Huang | 7cc5666 | 2010-10-15 02:02:57 +0800 | [diff] [blame] | 174 | __LIBC_HIDDEN__ | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 175 | struct __res_state _nres; | 
|  | 176 |  | 
|  | 177 | #if 0 | 
|  | 178 | struct resolv_cache* | 
|  | 179 | __get_res_cache(void) | 
|  | 180 | { | 
|  | 181 | _res_thread*  rt = _res_thread_get(); | 
|  | 182 |  | 
|  | 183 | if (!rt) | 
|  | 184 | return NULL; | 
|  | 185 |  | 
|  | 186 | if (!rt->_cache) { | 
|  | 187 | rt->_cache = _resolv_cache_create(); | 
|  | 188 | } | 
|  | 189 | return rt->_cache; | 
|  | 190 | } | 
|  | 191 | #endif | 
|  | 192 |  | 
|  | 193 | int* | 
|  | 194 | __get_h_errno(void) | 
|  | 195 | { | 
|  | 196 | _res_thread*  rt    = _res_thread_get(); | 
|  | 197 | static int    panic = NETDB_INTERNAL; | 
|  | 198 |  | 
|  | 199 | return rt ? &rt->_h_errno : &panic; | 
|  | 200 | } | 
|  | 201 |  | 
|  | 202 | res_state | 
|  | 203 | __res_get_state(void) | 
|  | 204 | { | 
|  | 205 | _res_thread*  rt = _res_thread_get(); | 
|  | 206 |  | 
|  | 207 | return rt ? rt->_nres : NULL; | 
|  | 208 | } | 
|  | 209 |  | 
|  | 210 | void | 
| Elliott Hughes | 68c2755 | 2014-07-07 09:44:17 -0700 | [diff] [blame] | 211 | __res_put_state(res_state res __unused) | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 212 | { | 
|  | 213 | /* nothing to do */ | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 214 | } | 
|  | 215 |  | 
|  | 216 | res_static | 
|  | 217 | __res_get_static(void) | 
|  | 218 | { | 
|  | 219 | _res_thread*  rt = _res_thread_get(); | 
|  | 220 |  | 
|  | 221 | return rt ? rt->_rstatic : NULL; | 
|  | 222 | } |