michael@0: /* michael@0: * Copyright (C) 2008 The Android Open Source Project michael@0: * All rights reserved. michael@0: * michael@0: * Redistribution and use in source and binary forms, with or without michael@0: * modification, are permitted provided that the following conditions michael@0: * are met: michael@0: * * Redistributions of source code must retain the above copyright michael@0: * notice, this list of conditions and the following disclaimer. michael@0: * * Redistributions in binary form must reproduce the above copyright michael@0: * notice, this list of conditions and the following disclaimer in michael@0: * the documentation and/or other materials provided with the michael@0: * distribution. michael@0: * michael@0: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS michael@0: * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE michael@0: * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, michael@0: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, michael@0: * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS michael@0: * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED michael@0: * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, michael@0: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT michael@0: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF michael@0: * SUCH DAMAGE. michael@0: */ michael@0: michael@0: /* michael@0: * This version of this file is derived from Android 2.3 "Gingerbread", michael@0: * which contains uncredited changes by Android/Google developers. It has michael@0: * been modified in 2011 for use in the Android build of Mozilla Firefox by michael@0: * Mozilla contributors (including Michael Edwards , michael@0: * and Steve Workman ). michael@0: * These changes are offered under the same license as the original NetBSD michael@0: * file, whose copyright and license are unchanged above. michael@0: */ michael@0: michael@0: /* michael@0: * This version of this file is derived from Android 2.3 "Gingerbread", michael@0: * which contains uncredited changes by Android/Google developers. It has michael@0: * been modified in 2011 for use in the Android build of Mozilla Firefox by michael@0: * Mozilla contributors (including Michael Edwards , michael@0: * and Steve Workman ). michael@0: * These changes are offered under the same license as the original NetBSD michael@0: * file, whose copyright and license are unchanged above. michael@0: */ michael@0: michael@0: #define ANDROID_CHANGES 1 michael@0: #define MOZILLA_NECKO_EXCLUDE_CODE 1 michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include "arpa_nameser.h" michael@0: #include michael@0: #include "resolv_private.h" michael@0: #include "resolv_cache.h" michael@0: #include michael@0: #include michael@0: michael@0: #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ michael@0: #include michael@0: michael@0: static pthread_key_t _res_key; michael@0: static pthread_once_t _res_once; michael@0: michael@0: typedef struct { michael@0: int _h_errno; michael@0: struct __res_state _nres[1]; michael@0: unsigned _serial; michael@0: struct prop_info* _pi; michael@0: struct res_static _rstatic[1]; michael@0: } _res_thread; michael@0: michael@0: static _res_thread* michael@0: _res_thread_alloc(void) michael@0: { michael@0: _res_thread* rt = malloc(sizeof(*rt)); michael@0: michael@0: if (rt) { michael@0: rt->_h_errno = 0; michael@0: /* Special system property which tracks any changes to 'net.*'. */ michael@0: rt->_serial = 0; michael@0: rt->_pi = (struct prop_info*) __system_property_find("net.change"); michael@0: if (rt->_pi) { michael@0: rt->_serial = rt->_pi->serial; michael@0: } michael@0: if ( res_ninit( rt->_nres ) < 0 ) { michael@0: free(rt); michael@0: rt = NULL; michael@0: } else { michael@0: memset(rt->_rstatic, 0, sizeof rt->_rstatic); michael@0: } michael@0: } michael@0: return rt; michael@0: } michael@0: michael@0: static void michael@0: _res_static_done( res_static rs ) michael@0: { michael@0: /* fortunately, there is nothing to do here, since the michael@0: * points in h_addr_ptrs and host_aliases should all michael@0: * point to 'hostbuf' michael@0: */ michael@0: if (rs->hostf) { /* should not happen in theory, but just be safe */ michael@0: fclose(rs->hostf); michael@0: rs->hostf = NULL; michael@0: } michael@0: free(rs->servent.s_aliases); michael@0: } michael@0: michael@0: static void michael@0: _res_thread_free( void* _rt ) michael@0: { michael@0: _res_thread* rt = _rt; michael@0: michael@0: _res_static_done(rt->_rstatic); michael@0: res_ndestroy(rt->_nres); michael@0: free(rt); michael@0: } michael@0: michael@0: static void michael@0: _res_init_key( void ) michael@0: { michael@0: pthread_key_create( &_res_key, _res_thread_free ); michael@0: } michael@0: michael@0: static _res_thread* michael@0: _res_thread_get(void) michael@0: { michael@0: _res_thread* rt; michael@0: pthread_once( &_res_once, _res_init_key ); michael@0: rt = pthread_getspecific( _res_key ); michael@0: if (rt == NULL) { michael@0: if ((rt = _res_thread_alloc()) == NULL) { michael@0: return NULL; michael@0: } michael@0: rt->_h_errno = 0; michael@0: rt->_serial = 0; michael@0: pthread_setspecific( _res_key, rt ); michael@0: } michael@0: /* Check the serial value for any chanes to net.* properties. */ michael@0: if (rt->_pi == NULL) { michael@0: rt->_pi = (struct prop_info*) __system_property_find("net.change"); michael@0: } michael@0: if (rt->_pi == NULL || rt->_serial == rt->_pi->serial) { michael@0: return rt; michael@0: } michael@0: rt->_serial = rt->_pi->serial; michael@0: /* Reload from system properties. */ michael@0: if ( res_ninit( rt->_nres ) < 0 ) { michael@0: free(rt); michael@0: rt = NULL; michael@0: pthread_setspecific( _res_key, rt ); michael@0: } michael@0: #ifdef USE_RESOLV_CACHE michael@0: _resolv_cache_reset(rt->_serial); michael@0: #endif michael@0: return rt; michael@0: } michael@0: michael@0: struct __res_state _nres; michael@0: michael@0: #if 0 michael@0: struct resolv_cache* michael@0: __get_res_cache(void) michael@0: { michael@0: _res_thread* rt = _res_thread_get(); michael@0: michael@0: if (!rt) michael@0: return NULL; michael@0: michael@0: if (!rt->_cache) { michael@0: rt->_cache = _resolv_cache_create(); michael@0: } michael@0: return rt->_cache; michael@0: } michael@0: #endif michael@0: michael@0: int* michael@0: __get_h_errno(void) michael@0: { michael@0: _res_thread* rt = _res_thread_get(); michael@0: static int panic = NETDB_INTERNAL; michael@0: michael@0: return rt ? &rt->_h_errno : &panic; michael@0: } michael@0: michael@0: res_state michael@0: __res_get_state(void) michael@0: { michael@0: _res_thread* rt = _res_thread_get(); michael@0: michael@0: return rt ? rt->_nres : NULL; michael@0: } michael@0: michael@0: void michael@0: __res_put_state(res_state res) michael@0: { michael@0: /* nothing to do */ michael@0: res=res; michael@0: } michael@0: michael@0: res_static michael@0: __res_get_static(void) michael@0: { michael@0: _res_thread* rt = _res_thread_get(); michael@0: michael@0: return rt ? rt->_rstatic : NULL; michael@0: }