| 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 |  | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 39 |  | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 40 | /* Set to 1 to enable debug traces */ | 
 | 41 | #define DEBUG 0 | 
 | 42 |  | 
 | 43 | #if DEBUG | 
| Christopher Ferris | 7a3681e | 2017-04-24 17:48:32 -0700 | [diff] [blame] | 44 | #  include <async_safe/log.h> | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 45 | #  include <unistd.h>  /* for gettid() */ | 
| Christopher Ferris | 7a3681e | 2017-04-24 17:48:32 -0700 | [diff] [blame] | 46 | #  define D(...) async_safe_format_log(ANDROID_LOG_DEBUG,"libc", __VA_ARGS__) | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 47 | #else | 
 | 48 | #  define D(...)  do{}while(0) | 
 | 49 | #endif | 
 | 50 |  | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 51 | typedef struct { | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 52 |     int                  _h_errno; | 
| Szymon Jakubczak | ea9bf67 | 2014-02-14 17:07:23 -0500 | [diff] [blame] | 53 |     // 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] | 54 |     struct __res_state  _nres[1]; | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 55 |     struct res_static   _rstatic[1]; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 56 | } _res_thread; | 
 | 57 |  | 
 | 58 | static _res_thread* | 
 | 59 | _res_thread_alloc(void) | 
 | 60 | { | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 61 |     _res_thread*  rt = calloc(1, sizeof(*rt)); | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 62 |  | 
 | 63 |     if (rt) { | 
 | 64 |         rt->_h_errno = 0; | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 65 |         memset(rt->_rstatic, 0, sizeof rt->_rstatic); | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 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 |  | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 89 |     D("%s: rt=%p for thread=%d", __FUNCTION__, rt, gettid()); | 
 | 90 |  | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 91 |     _res_static_done(rt->_rstatic); | 
 | 92 |     res_ndestroy(rt->_nres); | 
 | 93 |     free(rt); | 
 | 94 | } | 
 | 95 |  | 
| Elliott Hughes | 6170693 | 2015-03-31 10:56:58 -0700 | [diff] [blame] | 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 | } | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 101 |  | 
 | 102 | static _res_thread* | 
 | 103 | _res_thread_get(void) | 
 | 104 | { | 
 | 105 |     _res_thread*  rt; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 106 |     rt = pthread_getspecific( _res_key ); | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 107 |  | 
 | 108 |     if (rt != NULL) { | 
| Erik Kline | 40d51f0 | 2016-12-05 10:42:12 +0900 | [diff] [blame] | 109 |         return rt; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 110 |     } | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 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; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 117 |     } | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 118 |     pthread_setspecific( _res_key, rt ); | 
 | 119 |     D("%s: tid=%d Created new DNS state rt=%p", | 
 | 120 |       __FUNCTION__, gettid(), rt); | 
 | 121 |  | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 122 |     /* Reset the state, note that res_ninit() can now properly reset | 
 | 123 |      * an existing state without leaking memory. | 
 | 124 |      */ | 
| Erik Kline | 40d51f0 | 2016-12-05 10:42:12 +0900 | [diff] [blame] | 125 |     D("%s: tid=%d, rt=%p, setting DNS state (options RES_INIT=%d)", | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 126 |       __FUNCTION__, gettid(), rt, (rt->_nres->options & RES_INIT) != 0); | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 127 |     if ( res_ninit( rt->_nres ) < 0 ) { | 
| David 'Digit' Turner | b6cd681 | 2011-03-17 21:31:33 +0100 | [diff] [blame] | 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; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 134 |     } | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 135 |     return rt; | 
 | 136 | } | 
 | 137 |  | 
| Jim Huang | 7cc5666 | 2010-10-15 02:02:57 +0800 | [diff] [blame] | 138 | __LIBC_HIDDEN__ | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 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 | 
| Elliott Hughes | 68c2755 | 2014-07-07 09:44:17 -0700 | [diff] [blame] | 175 | __res_put_state(res_state res __unused) | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 176 | { | 
 | 177 |     /* nothing to do */ | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 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 | } |