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 #include <string.h> 38 39 40 /* Set to 1 to enable debug traces */ 41 #define DEBUG 0 42 43 #if DEBUG 44 # include <async_safe/log.h> 45 # include <unistd.h> /* for gettid() */ 46 # define D(...) async_safe_format_log(ANDROID_LOG_DEBUG,"libc", __VA_ARGS__) 47 #else 48 # define D(...) do{}while(0) 49 #endif 50 51 typedef struct { 52 int _h_errno; 53 // TODO: Have one __res_state per network so we don't have to repopulate frequently. 54 struct __res_state _nres[1]; 55 struct res_static _rstatic[1]; 56 } _res_thread; 57 58 static _res_thread* 59 _res_thread_alloc(void) 60 { 61 _res_thread* rt = calloc(1, sizeof(*rt)); 62 63 if (rt) { 64 rt->_h_errno = 0; 65 memset(rt->_rstatic, 0, sizeof rt->_rstatic); 66 } 67 return rt; 68 } 69 70 static void 71 _res_static_done( res_static rs ) 72 { 73 /* fortunately, there is nothing to do here, since the 74 * points in h_addr_ptrs and host_aliases should all 75 * point to 'hostbuf' 76 */ 77 if (rs->hostf) { /* should not happen in theory, but just be safe */ 78 fclose(rs->hostf); 79 rs->hostf = NULL; 80 } 81 free(rs->servent.s_aliases); 82 } 83 84 static void 85 _res_thread_free( void* _rt ) 86 { 87 _res_thread* rt = _rt; 88 89 D("%s: rt=%p for thread=%d", __FUNCTION__, rt, gettid()); 90 91 _res_static_done(rt->_rstatic); 92 res_ndestroy(rt->_nres); 93 free(rt); 94 } 95 96 static pthread_key_t _res_key; 97 98 __attribute__((constructor)) static void __res_key_init() { 99 pthread_key_create(&_res_key, _res_thread_free); 100 } 101 102 static _res_thread* 103 _res_thread_get(void) 104 { 105 _res_thread* rt; 106 rt = pthread_getspecific( _res_key ); 107 108 if (rt != NULL) { 109 return rt; 110 } 111 112 /* It is the first time this function is called in this thread, 113 * we need to create a new thread-specific DNS resolver state. */ 114 rt = _res_thread_alloc(); 115 if (rt == NULL) { 116 return NULL; 117 } 118 pthread_setspecific( _res_key, rt ); 119 D("%s: tid=%d Created new DNS state rt=%p", 120 __FUNCTION__, gettid(), rt); 121 122 /* Reset the state, note that res_ninit() can now properly reset 123 * an existing state without leaking memory. 124 */ 125 D("%s: tid=%d, rt=%p, setting DNS state (options RES_INIT=%d)", 126 __FUNCTION__, gettid(), rt, (rt->_nres->options & RES_INIT) != 0); 127 if ( res_ninit( rt->_nres ) < 0 ) { 128 /* This should not happen */ 129 D("%s: tid=%d rt=%p, woot, res_ninit() returned < 0", 130 __FUNCTION__, gettid(), rt); 131 _res_thread_free(rt); 132 pthread_setspecific( _res_key, NULL ); 133 return NULL; 134 } 135 return rt; 136 } 137 138 __LIBC_HIDDEN__ 139 struct __res_state _nres; 140 141 #if 0 142 struct resolv_cache* 143 __get_res_cache(void) 144 { 145 _res_thread* rt = _res_thread_get(); 146 147 if (!rt) 148 return NULL; 149 150 if (!rt->_cache) { 151 rt->_cache = _resolv_cache_create(); 152 } 153 return rt->_cache; 154 } 155 #endif 156 157 int* 158 __get_h_errno(void) 159 { 160 _res_thread* rt = _res_thread_get(); 161 static int panic = NETDB_INTERNAL; 162 163 return rt ? &rt->_h_errno : &panic; 164 } 165 166 res_state 167 __res_get_state(void) 168 { 169 _res_thread* rt = _res_thread_get(); 170 171 return rt ? rt->_nres : NULL; 172 } 173 174 void 175 __res_put_state(res_state res __unused) 176 { 177 /* nothing to do */ 178 } 179 180 res_static 181 __res_get_static(void) 182 { 183 _res_thread* rt = _res_thread_get(); 184 185 return rt ? rt->_rstatic : NULL; 186 } 187