| 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> | 
|  | 31 | #include "arpa_nameser.h" | 
|  | 32 | #include <netdb.h> | 
|  | 33 | #include "resolv_private.h" | 
|  | 34 | #include "resolv_cache.h" | 
|  | 35 | #include <pthread.h> | 
|  | 36 | #include <stdlib.h> | 
|  | 37 |  | 
|  | 38 | #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ | 
|  | 39 | #include <sys/_system_properties.h> | 
|  | 40 |  | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 41 | /* Set to 1 to enable debug traces */ | 
|  | 42 | #define DEBUG 0 | 
|  | 43 |  | 
|  | 44 | #if DEBUG | 
| Elliott Hughes | eb847bc | 2013-10-09 15:50:50 -0700 | [diff] [blame] | 45 | #  include "private/libc_logging.h" | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 46 | #  include <unistd.h>  /* for gettid() */ | 
| Elliott Hughes | 8f2a5a0 | 2013-03-15 15:30:25 -0700 | [diff] [blame] | 47 | #  define D(...) __libc_format_log(ANDROID_LOG_DEBUG,"libc", __VA_ARGS__) | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 48 | #else | 
|  | 49 | #  define D(...)  do{}while(0) | 
|  | 50 | #endif | 
|  | 51 |  | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 52 | static pthread_key_t   _res_key; | 
| Mattias Falk | c63e590 | 2011-08-23 14:34:14 +0200 | [diff] [blame] | 53 | static pthread_once_t  _res_once = PTHREAD_ONCE_INIT; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 54 |  | 
|  | 55 | typedef struct { | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 56 | int                  _h_errno; | 
|  | 57 | struct __res_state  _nres[1]; | 
|  | 58 | unsigned             _serial; | 
|  | 59 | struct prop_info*   _pi; | 
|  | 60 | struct res_static   _rstatic[1]; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 61 | } _res_thread; | 
|  | 62 |  | 
|  | 63 | static _res_thread* | 
|  | 64 | _res_thread_alloc(void) | 
|  | 65 | { | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 66 | _res_thread*  rt = calloc(1, sizeof(*rt)); | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 67 |  | 
|  | 68 | if (rt) { | 
|  | 69 | rt->_h_errno = 0; | 
|  | 70 | /* Special system property which tracks any changes to 'net.*'. */ | 
|  | 71 | rt->_serial = 0; | 
|  | 72 | rt->_pi = (struct prop_info*) __system_property_find("net.change"); | 
|  | 73 | if (rt->_pi) { | 
| Colin Cross | 5cf32de | 2013-01-23 23:07:06 -0800 | [diff] [blame] | 74 | rt->_serial = __system_property_serial(rt->_pi); | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 75 | } | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 76 | memset(rt->_rstatic, 0, sizeof rt->_rstatic); | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 77 | } | 
|  | 78 | return rt; | 
|  | 79 | } | 
|  | 80 |  | 
|  | 81 | static void | 
|  | 82 | _res_static_done( res_static  rs ) | 
|  | 83 | { | 
|  | 84 | /* fortunately, there is nothing to do here, since the | 
|  | 85 | * points in h_addr_ptrs and host_aliases should all | 
|  | 86 | * point to 'hostbuf' | 
|  | 87 | */ | 
|  | 88 | if (rs->hostf) {  /* should not happen in theory, but just be safe */ | 
|  | 89 | fclose(rs->hostf); | 
|  | 90 | rs->hostf = NULL; | 
|  | 91 | } | 
|  | 92 | free(rs->servent.s_aliases); | 
|  | 93 | } | 
|  | 94 |  | 
|  | 95 | static void | 
|  | 96 | _res_thread_free( void*  _rt ) | 
|  | 97 | { | 
|  | 98 | _res_thread*  rt = _rt; | 
|  | 99 |  | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 100 | D("%s: rt=%p for thread=%d", __FUNCTION__, rt, gettid()); | 
|  | 101 |  | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 102 | _res_static_done(rt->_rstatic); | 
|  | 103 | res_ndestroy(rt->_nres); | 
|  | 104 | free(rt); | 
|  | 105 | } | 
|  | 106 |  | 
|  | 107 | static void | 
|  | 108 | _res_init_key( void ) | 
|  | 109 | { | 
|  | 110 | pthread_key_create( &_res_key, _res_thread_free ); | 
|  | 111 | } | 
|  | 112 |  | 
|  | 113 | static _res_thread* | 
|  | 114 | _res_thread_get(void) | 
|  | 115 | { | 
|  | 116 | _res_thread*  rt; | 
|  | 117 | pthread_once( &_res_once, _res_init_key ); | 
|  | 118 | rt = pthread_getspecific( _res_key ); | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 119 |  | 
|  | 120 | if (rt != NULL) { | 
|  | 121 | /* We already have one thread-specific DNS state object. | 
|  | 122 | * Check the serial value for any changes to net.* properties */ | 
|  | 123 | D("%s: Called for tid=%d rt=%p rt->pi=%p rt->serial=%d", | 
|  | 124 | __FUNCTION__, gettid(), rt, rt->_pi, rt->_serial); | 
|  | 125 | if (rt->_pi == NULL) { | 
|  | 126 | /* The property wasn't created when _res_thread_get() was | 
|  | 127 | * called the last time. This should only happen very | 
|  | 128 | * early during the boot sequence. First, let's try to see if it | 
|  | 129 | * is here now. */ | 
|  | 130 | rt->_pi = (struct prop_info*) __system_property_find("net.change"); | 
|  | 131 | if (rt->_pi == NULL) { | 
|  | 132 | /* Still nothing, return current state */ | 
|  | 133 | D("%s: exiting for tid=%d rt=%d since system property not found", | 
|  | 134 | __FUNCTION__, gettid(), rt); | 
|  | 135 | return rt; | 
|  | 136 | } | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 137 | } | 
| Colin Cross | 5cf32de | 2013-01-23 23:07:06 -0800 | [diff] [blame] | 138 | if (rt->_serial == __system_property_serial(rt->_pi)) { | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 139 | /* Nothing changed, so return the current state */ | 
|  | 140 | D("%s: tid=%d rt=%p nothing changed, returning", | 
|  | 141 | __FUNCTION__, gettid(), rt); | 
|  | 142 | return rt; | 
|  | 143 | } | 
|  | 144 | /* Update the recorded serial number, and go reset the state */ | 
| Colin Cross | 5cf32de | 2013-01-23 23:07:06 -0800 | [diff] [blame] | 145 | rt->_serial = __system_property_serial(rt->_pi); | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 146 | goto RESET_STATE; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 147 | } | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 148 |  | 
|  | 149 | /* It is the first time this function is called in this thread, | 
|  | 150 | * we need to create a new thread-specific DNS resolver state. */ | 
|  | 151 | rt = _res_thread_alloc(); | 
|  | 152 | if (rt == NULL) { | 
|  | 153 | return NULL; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 154 | } | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 155 | pthread_setspecific( _res_key, rt ); | 
|  | 156 | D("%s: tid=%d Created new DNS state rt=%p", | 
|  | 157 | __FUNCTION__, gettid(), rt); | 
|  | 158 |  | 
|  | 159 | RESET_STATE: | 
|  | 160 | /* Reset the state, note that res_ninit() can now properly reset | 
|  | 161 | * an existing state without leaking memory. | 
|  | 162 | */ | 
|  | 163 | D("%s: tid=%d, rt=%p, resetting DNS state (options RES_INIT=%d)", | 
|  | 164 | __FUNCTION__, gettid(), rt, (rt->_nres->options & RES_INIT) != 0); | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 165 | if ( res_ninit( rt->_nres ) < 0 ) { | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 166 | /* This should not happen */ | 
|  | 167 | D("%s: tid=%d rt=%p, woot, res_ninit() returned < 0", | 
|  | 168 | __FUNCTION__, gettid(), rt); | 
|  | 169 | _res_thread_free(rt); | 
|  | 170 | pthread_setspecific( _res_key, NULL ); | 
|  | 171 | return NULL; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 172 | } | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 173 | return rt; | 
|  | 174 | } | 
|  | 175 |  | 
| Jim Huang | 7cc5666 | 2010-10-15 02:02:57 +0800 | [diff] [blame] | 176 | __LIBC_HIDDEN__ | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 177 | struct __res_state _nres; | 
|  | 178 |  | 
|  | 179 | #if 0 | 
|  | 180 | struct resolv_cache* | 
|  | 181 | __get_res_cache(void) | 
|  | 182 | { | 
|  | 183 | _res_thread*  rt = _res_thread_get(); | 
|  | 184 |  | 
|  | 185 | if (!rt) | 
|  | 186 | return NULL; | 
|  | 187 |  | 
|  | 188 | if (!rt->_cache) { | 
|  | 189 | rt->_cache = _resolv_cache_create(); | 
|  | 190 | } | 
|  | 191 | return rt->_cache; | 
|  | 192 | } | 
|  | 193 | #endif | 
|  | 194 |  | 
|  | 195 | int* | 
|  | 196 | __get_h_errno(void) | 
|  | 197 | { | 
|  | 198 | _res_thread*  rt    = _res_thread_get(); | 
|  | 199 | static int    panic = NETDB_INTERNAL; | 
|  | 200 |  | 
|  | 201 | return rt ? &rt->_h_errno : &panic; | 
|  | 202 | } | 
|  | 203 |  | 
|  | 204 | res_state | 
|  | 205 | __res_get_state(void) | 
|  | 206 | { | 
|  | 207 | _res_thread*  rt = _res_thread_get(); | 
|  | 208 |  | 
|  | 209 | return rt ? rt->_nres : NULL; | 
|  | 210 | } | 
|  | 211 |  | 
|  | 212 | void | 
|  | 213 | __res_put_state(res_state res) | 
|  | 214 | { | 
|  | 215 | /* nothing to do */ | 
|  | 216 | res=res; | 
|  | 217 | } | 
|  | 218 |  | 
|  | 219 | res_static | 
|  | 220 | __res_get_static(void) | 
|  | 221 | { | 
|  | 222 | _res_thread*  rt = _res_thread_get(); | 
|  | 223 |  | 
|  | 224 | return rt ? rt->_rstatic : NULL; | 
|  | 225 | } |