res_state.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  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. #define LOG_TAG "res_state"
  29. #include <arpa/inet.h>
  30. #include <arpa/nameser.h>
  31. #include <netdb.h>
  32. #include <pthread.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include <sys/types.h>
  36. #include <unistd.h> /* for gettid() */
  37. #include <android-base/logging.h>
  38. #include "resolv_cache.h"
  39. #include "resolv_private.h"
  40. typedef struct {
  41. // TODO: Have one __res_state per network so we don't have to repopulate frequently.
  42. struct __res_state _nres[1];
  43. struct res_static _rstatic[1];
  44. } _res_thread;
  45. static _res_thread* res_thread_alloc(void) {
  46. _res_thread* rt = (_res_thread*) calloc(1, sizeof(*rt));
  47. if (rt) {
  48. memset(rt->_rstatic, 0, sizeof rt->_rstatic);
  49. }
  50. return rt;
  51. }
  52. static void res_static_done(struct res_static* rs) {
  53. /* fortunately, there is nothing to do here, since the
  54. * points in h_addr_ptrs and host_aliases should all
  55. * point to 'hostbuf'
  56. */
  57. if (rs->hostf) { /* should not happen in theory, but just be safe */
  58. fclose(rs->hostf);
  59. rs->hostf = NULL;
  60. }
  61. free(rs->servent.s_aliases);
  62. }
  63. static void res_thread_free(void* _rt) {
  64. _res_thread* rt = (_res_thread*) _rt;
  65. LOG(VERBOSE) << __func__ << ": rt=" << rt << " for thread=" << gettid();
  66. res_static_done(rt->_rstatic);
  67. res_ndestroy(rt->_nres);
  68. free(rt);
  69. }
  70. static pthread_key_t _res_key;
  71. __attribute__((constructor)) static void __res_key_init() {
  72. pthread_key_create(&_res_key, res_thread_free);
  73. }
  74. static _res_thread* res_thread_get(void) {
  75. _res_thread* rt = (_res_thread*) pthread_getspecific(_res_key);
  76. if (rt != NULL) {
  77. return rt;
  78. }
  79. /* It is the first time this function is called in this thread,
  80. * we need to create a new thread-specific DNS resolver state. */
  81. rt = res_thread_alloc();
  82. if (rt == NULL) {
  83. return NULL;
  84. }
  85. pthread_setspecific(_res_key, rt);
  86. /* Reset the state, note that res_ninit() can now properly reset
  87. * an existing state without leaking memory.
  88. */
  89. LOG(VERBOSE) << __func__ << ": tid=" << gettid() << ", rt=" << rt
  90. << " setting DNS state (options=" << rt->_nres->options << ")";
  91. if (res_ninit(rt->_nres) < 0) {
  92. /* This should not happen */
  93. LOG(VERBOSE) << __func__ << ": tid=" << gettid() << " rt=" << rt
  94. << ", res_ninit() returned < 0";
  95. res_thread_free(rt);
  96. pthread_setspecific(_res_key, NULL);
  97. return NULL;
  98. }
  99. return rt;
  100. }
  101. struct __res_state _nres;
  102. res_state res_get_state(void) {
  103. _res_thread* rt = res_thread_get();
  104. return rt ? rt->_nres : NULL;
  105. }
  106. res_static* res_get_static(void) {
  107. _res_thread* rt = res_thread_get();
  108. return rt ? rt->_rstatic : NULL;
  109. }