1 /* 2 * Copyright (c) 1998-2000 by Sun Microsystems, Inc. 3 */ 4 5 #pragma ident "%Z%%M% %I% %E% SMI" 6 7 #include <port_before.h> 8 #include <thread.h> 9 #include <errno.h> 10 #include <netdb.h> 11 #include <malloc.h> 12 #include <string.h> 13 #include <resolv_mt.h> 14 #include <irs.h> 15 #include <port_after.h> 16 17 static int thr_keycreate_ret = 0; 18 19 static thread_key_t key; 20 static int mt_key_initialized = 0; 21 22 static mtctxres_t sharedctx; 23 24 static int __res_init_ctx(thread_key_t); 25 static void __res_destroy_ctx(void *); 26 27 #pragma init (_mtctxres_init) 28 29 /* 30 * Initialize the TSD key. By doing this at library load time, we're 31 * implicitly running without interference from other threads, so there's 32 * no need for locking. 33 */ 34 static void 35 _mtctxres_init(void) { 36 37 if ((thr_keycreate_ret = thr_keycreate(&key, __res_destroy_ctx)) == 0) { 38 mt_key_initialized = 1; 39 } 40 } 41 42 43 /* 44 * To support binaries that used the private MT-safe interface in 45 * on998 or on28, we still need to provide the __res_enable_mt() 46 * and __res_disable_mt() entry points. They're do-nothing routines. 47 */ 48 int 49 __res_enable_mt(void) { 50 return (-1); 51 } 52 53 int 54 __res_disable_mt(void) { 55 return (0); 56 } 57 58 59 static int 60 __res_init_ctx(thread_key_t key) { 61 62 mtctxres_t *mt; 63 int ret; 64 65 66 if (thr_getspecific(key, (void **)&mt) == 0 && mt != 0) { 67 /* Already exists */ 68 return (0); 69 } 70 71 if ((mt = malloc(sizeof (mtctxres_t))) == 0) { 72 errno = ENOMEM; 73 return (-1); 74 } 75 76 memset(mt, 0, sizeof (*mt)); 77 78 if ((ret = thr_setspecific(key, mt)) != 0) { 79 errno = ret; 80 free(mt); 81 return (-1); 82 } 83 84 return (0); 85 86 } 87 88 89 static void 90 __res_destroy_ctx(void *value) { 91 92 mtctxres_t *mt = (mtctxres_t *)value; 93 94 if (mt != 0) { 95 free(mt); 96 } 97 } 98 99 100 mtctxres_t * 101 ___mtctxres() { 102 103 mtctxres_t *mt; 104 105 106 if (mt_key_initialized) { 107 if ((thr_getspecific(key, (void **)&mt) == 0 && mt != 0) || 108 (__res_init_ctx(key) == 0 && 109 thr_getspecific(key, (void **)&mt) == 0 && mt != 0)) { 110 return (mt); 111 } 112 } 113 114 return (&sharedctx); 115 } 116 117 118 /* 119 * There used to be a private, MT-safe resolver interface that used TSD 120 * to store per-thread _res, h_errno, etc. We continue to provide the 121 * access functions __res_get_res() and __res_get_h_errno() so that binaries 122 * that used the private interface will continue to work. 123 */ 124 125 #ifdef _res 126 #undef _res 127 #endif 128 129 extern struct __res_state *__res_state(void); 130 131 struct __res_state * 132 __res_get_res(void) { 133 return (__res_state()); 134 } 135 136 137 #ifdef h_errno 138 #undef h_errno 139 #endif 140 141 extern int *__h_errno(void); 142 143 int * 144 __res_get_h_errno(void) { 145 return (__h_errno()); 146 } 147 148 149 #ifdef SUNW_HOSTS_FALLBACK 150 151 /* 152 * When the name service switch calls libresolv, it doesn't want fallback 153 * to /etc/hosts, so we provide a method to turn it off. 154 */ 155 156 void 157 __res_set_no_hosts_fallback(void) { 158 ___mtctxres()->no_hosts_fallback_private = 1; 159 } 160 161 void 162 __res_unset_no_hosts_fallback(void) { 163 ___mtctxres()->no_hosts_fallback_private = 0; 164 } 165 166 int 167 __res_no_hosts_fallback(void) { 168 return (___mtctxres()->no_hosts_fallback_private); 169 } 170 171 #endif /* SUNW_HOSTS_FALLBACK */ 172 173 #ifdef SUNW_OVERRIDE_RETRY 174 175 /* 176 * The NS switch wants to be able to override the number of retries. 177 */ 178 179 int 180 __res_override_retry(int retry) { 181 ___mtctxres()->retry_private = retry; 182 /* 183 * This function doesn't really need a return value; saving the 184 * old retry setting, and restoring it, is handled by __res_retry() 185 * and __res_retry_reset() below. However, the nss_dns library 186 * must have a private version of this function to be used when 187 * running with an old libresolv. That private nss_dns function 188 * needs a return value, and a function pointer is used to select 189 * the right function at runtime. Thus, __res_override_retry 190 * must have a function prototype consistent with the private 191 * nss_dns function, i.e., one that returns an int. 192 * 193 * Given that we do have a return value, that value must be zero. 194 * That's because retry_private == 0 is used to indicate that 195 * no override retry value is in effect, and the way we expect 196 * nss_dns to call us is: 197 * 198 * int oldretry = __res_override_retry(N); 199 * <whatever> 200 * (void)__res_override_retry(old_retry); 201 */ 202 return (0); 203 } 204 205 int 206 __res_retry(int retry) { 207 mtctxres_t *mt = ___mtctxres(); 208 209 mt->retry_save = retry; 210 return ((mt->retry_private != 0) ? mt->retry_private : retry); 211 } 212 213 int 214 __res_retry_reset(void) { 215 mtctxres_t *mt = ___mtctxres(); 216 217 return (mt->retry_save); 218 } 219 220 #endif /* SUNW_OVERRIDE_RETRY */ 221