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 55struct __res_state _nres 56# if defined(__BIND_RES_TEXT) 57 = { .retrans = RES_TIMEOUT, } /*%< Motorola, et al. */ 58# endif 59 ; 60 61static SLIST_HEAD(, _res_st) res_list = LIST_HEAD_INITIALIZER(&res_list); 62 63struct _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 70static pthread_mutex_t res_mtx = PTHREAD_MUTEX_INITIALIZER; 71 72res_state __res_state(void); 73res_state __res_get_state(void); 74void __res_put_state(res_state); 75 76#ifdef RES_STATE_DEBUG 77static void 78res_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 91res_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 124void 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 */ 141res_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