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 41 /* Set to 1 to enable debug traces */ 42 #define DEBUG 0 43 44 #if DEBUG 45 # include "libc_logging.h" 46 # include <unistd.h> /* for gettid() */ 47 # define D(...) __libc_format_log(ANDROID_LOG_DEBUG,"libc", __VA_ARGS__) 48 #else 49 # define D(...) do{}while(0) 50 #endif 51 52 static pthread_key_t _res_key; 53 static pthread_once_t _res_once = PTHREAD_ONCE_INIT; 54 55 typedef struct { 56 int _h_errno; 57 struct __res_state _nres[1]; 58 unsigned _serial; 59 struct prop_info* _pi; 60 struct res_static _rstatic[1]; 61 } _res_thread; 62 63 static _res_thread* 64 _res_thread_alloc(void) 65 { 66 _res_thread* rt = calloc(1, sizeof(*rt)); 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) { 74 rt->_serial = rt->_pi->serial; 75 } 76 memset(rt->_rstatic, 0, sizeof rt->_rstatic); 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 100 D("%s: rt=%p for thread=%d", __FUNCTION__, rt, gettid()); 101 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 ); 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 } 137 } 138 if (rt->_serial == rt->_pi->serial) { 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 */ 145 rt->_serial = rt->_pi->serial; 146 goto RESET_STATE; 147 } 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; 154 } 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); 165 if ( res_ninit( rt->_nres ) < 0 ) { 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; 172 } 173 return rt; 174 } 175 176 __LIBC_HIDDEN__ 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 } 226