1 /* $NetBSD: res_state.c,v 1.6 2008/04/28 20:23:02 martin Exp $ */ 2 3 /*- 4 * Copyright (c) 2004 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Christos Zoulas. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* Note to Haiku Developers: 33 ------------------------- 34 This file contains the thread-safe versions of res functions, taken from 35 NetBSD's libpthread directory. Do *not* replace it with the legacy 36 single-threaded version from NetBSD's netresolv directory. 37 */ 38 39 #include <sys/cdefs.h> 40 #if defined(LIBC_SCCS) && !defined(lint) 41 __RCSID("$NetBSD: res_state.c,v 1.6 2008/04/28 20:23:02 martin Exp $"); 42 #endif 43 44 #include <sys/types.h> 45 #include <sys/queue.h> 46 #include <arpa/inet.h> 47 #include <arpa/nameser.h> 48 #include <stdlib.h> 49 #include <unistd.h> 50 #include <resolv.h> 51 #include <netdb.h> 52 53 #include <pthread.h> 54 55 struct __res_state _nres 56 # if defined(__BIND_RES_TEXT) 57 = { .retrans = RES_TIMEOUT, } /*%< Motorola, et al. */ 58 # endif 59 ; 60 61 static SLIST_HEAD(, _res_st) res_list = LIST_HEAD_INITIALIZER(&res_list); 62 63 struct _res_st { 64 /* __res_put_state() assumes st_res is the first member. */ 65 struct __res_state st_res; 66 67 SLIST_ENTRY(_res_st) st_list; 68 }; 69 70 static pthread_mutex_t res_mtx = PTHREAD_MUTEX_INITIALIZER; 71 72 res_state __res_state(void); 73 res_state __res_get_state(void); 74 void __res_put_state(res_state); 75 76 #ifdef RES_STATE_DEBUG 77 static void 78 res_state_debug(const char *msg, void *p) 79 { 80 char buf[512]; 81 pthread_t self = pthread__self(); 82 int len = snprintf(buf, sizeof(buf), "%p: %s %p\n", self, msg, p); 83 84 (void)write(STDOUT_FILENO, buf, (size_t)len); 85 } 86 #else 87 #define res_state_debug(a, b) 88 #endif 89 90 91 res_state 92 __res_get_state(void) 93 { 94 res_state res; 95 struct _res_st *st; 96 pthread_mutex_lock(&res_mtx); 97 st = SLIST_FIRST(&res_list); 98 if (st != NULL) { 99 SLIST_REMOVE_HEAD(&res_list, st_list); 100 pthread_mutex_unlock(&res_mtx); 101 res = &st->st_res; 102 res_state_debug("checkout from list", st); 103 } else { 104 pthread_mutex_unlock(&res_mtx); 105 st = malloc(sizeof(*st)); 106 if (st == NULL) { 107 h_errno = NETDB_INTERNAL; 108 return NULL; 109 } 110 res = &st->st_res; 111 res->options = 0; 112 res_state_debug("alloc new", res); 113 } 114 if ((res->options & RES_INIT) == 0) { 115 if (res_ninit(res) == -1) { 116 h_errno = NETDB_INTERNAL; 117 free(st); 118 return NULL; 119 } 120 } 121 return res; 122 } 123 124 void 125 /*ARGSUSED*/ 126 __res_put_state(res_state res) 127 { 128 struct _res_st *st = (struct _res_st *)(void *)res; 129 130 res_state_debug("free", res); 131 pthread_mutex_lock(&res_mtx); 132 SLIST_INSERT_HEAD(&res_list, st, st_list); 133 pthread_mutex_unlock(&res_mtx); 134 } 135 136 137 /* 138 * This is aliased via a macro to _res. 139 * This function is not thread safe. 140 */ 141 res_state 142 __res_state(void) 143 { 144 if ((_nres.options & RES_INIT) == 0 && res_ninit(&_nres) == -1) { 145 h_errno = NETDB_INTERNAL; 146 return NULL; 147 } 148 149 return &_nres; 150 } 151