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