res_internal.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:15k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*
  2.  * Copyright (c) 1985 Regents of the University of California.
  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.  * 1. Redistributions of source code must retain the above copyright
  9.  *   notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *   notice, this list of conditions and the following disclaimer in the
  12.  *   documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *   must display the following acknowledgement:
  15.  * This product includes software developed by the University of
  16.  * California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *   may be used to endorse or promote products derived from this software
  19.  *   without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33. #if defined(LIBC_SCCS) && !defined(lint)
  34. /*static char *sccsid = "from: @(#)res_internal.c 6.22 (Berkeley) 3/19/91";*/
  35. static char *rcsid = "$Id$";
  36. #endif /* LIBC_SCCS and not lint */
  37. #include <pthread.h>
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include <resolv.h>
  41. #include <netdb.h>
  42. #include <sys/socket.h>
  43. #include <netinet/in.h>
  44. #include <string.h>
  45. #include <errno.h>
  46. #include "res_internal.h"
  47. #define DEFAULT_RETRIES 4
  48. pthread_mutex_t host_iterate_lock = PTHREAD_MUTEX_INITIALIZER;
  49. static pthread_once_t init_once = PTHREAD_ONCE_INIT;
  50. static pthread_key_t key;
  51. static int init_status;
  52. static void _res_init_global(void);
  53. static void set_options(const char *options, const char *source);
  54. static pthread_ipaddr_type net_mask(struct in_addr in);
  55. static int qcomp(const void *arg1, const void *arg2);
  56. static struct __res_state start;
  57. /* We want to define _res for partial binary compatibility with libraries. */
  58. #undef _res
  59. struct __res_state _res = {
  60. RES_TIMEOUT,                /* retransmition time interval */
  61. 4,                          /* number of times to retransmit */
  62. RES_DEFAULT, /* options flags */
  63. 1,                          /* number of name servers */
  64. };
  65. struct hostent *_res_parse_answer(querybuf *answer, int anslen, int iquery,
  66.   struct hostent *result, char *buf,
  67.   int bufsize, int *errval)
  68. {
  69. struct res_data *data = _res_init();
  70. register HEADER *hp;
  71. register u_char *cp;
  72. register int n;
  73. u_char *eom;
  74. char *aliases[__NETDB_MAXALIASES], *addrs[__NETDB_MAXADDRS];
  75. char *bp = buf, **ap = aliases, **hap = addrs;
  76. int type, class, ancount, qdcount, getclass = C_ANY, iquery_done = 0;
  77. eom = answer->buf + anslen;
  78. /*
  79.  * find first satisfactory answer
  80.  */
  81. hp = &answer->hdr;
  82. ancount = ntohs(hp->ancount);
  83. qdcount = ntohs(hp->qdcount);
  84. bp = buf;
  85. cp = answer->buf + sizeof(HEADER);
  86. /* Read in the hostname if this is an address lookup. */
  87. if (qdcount) {
  88. if (iquery) {
  89. if ((n = dn_expand((u_char *) answer->buf,
  90.    (u_char *) eom, (u_char *) cp, (u_char *) bp,
  91.    bufsize - (bp - buf))) < 0) {
  92. *errval = NO_RECOVERY;
  93. return ((struct hostent *) NULL);
  94. }
  95. cp += n + QFIXEDSZ;
  96. result->h_name = bp;
  97. bp += strlen(bp) + 1;
  98. } else {
  99. cp += __dn_skipname(cp, eom) + QFIXEDSZ;
  100. }
  101. while (--qdcount > 0)
  102. cp += __dn_skipname(cp, eom) + QFIXEDSZ;
  103. } else if (iquery) {
  104. *errval = (hp->aa) ? HOST_NOT_FOUND : TRY_AGAIN;
  105. return ((struct hostent *) NULL);
  106. }
  107. /* Read in the answers. */
  108. *ap = NULL;
  109. *hap = NULL;
  110. while (--ancount >= 0 && cp < eom) {
  111. if ((n = dn_expand((u_char *) answer->buf, (u_char *) eom,
  112.    (u_char *) cp, (u_char *) bp,
  113.    bufsize - (bp - buf))) < 0)
  114. break;
  115. cp += n;
  116. type = _getshort(cp);
  117. cp += sizeof(u_short);
  118. class = _getshort(cp);
  119. cp += sizeof(u_short) + sizeof(pthread_ipaddr_type);
  120. n = _getshort(cp);
  121. cp += sizeof(u_short);
  122. if (type == T_CNAME) {
  123. cp += n;
  124. if (ap >= aliases + __NETDB_MAXALIASES - 1)
  125. continue;
  126. *ap++ = bp;
  127. bp += strlen(bp) + 1;
  128. continue;
  129. }
  130. if (iquery && type == T_PTR) {
  131. if ((n = dn_expand((u_char *) answer->buf, (u_char *) eom,
  132.    (u_char *) cp, (u_char *) bp,
  133.    bufsize - (bp - buf))) < 0)
  134. break;
  135. cp += n;
  136. result->h_name = bp;
  137. bp += strlen(bp) + 1;
  138. iquery_done = 1;
  139. break;
  140. }
  141. if (iquery || type != T_A) {
  142. #ifdef DEBUG_RESOLVER
  143. if (data->state.options & RES_DEBUG)
  144. printf("unexpected answer type %d, size %dn",
  145.    type, n);
  146. #endif
  147. cp += n;
  148. continue;
  149. }
  150. if (hap > addrs) {
  151. if (n != result->h_length) {
  152. cp += n;
  153. continue;
  154. }
  155. if (class != getclass) {
  156. cp += n;
  157. continue;
  158. }
  159. } else {
  160. result->h_length = n;
  161. getclass = class;
  162. result->h_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC;
  163. if (!iquery) {
  164. result->h_name = bp;
  165. bp += strlen(bp) + 1;
  166. }
  167. }
  168. bp = ALIGN(bp, pthread_ipaddr_type);
  169. if (bp + n >= buf + bufsize) {
  170. errno = ERANGE;
  171. return NULL;
  172. }
  173. memcpy(bp, cp, n);
  174. cp += n;
  175. if (hap >= addrs + __NETDB_MAXADDRS - 1)
  176. continue;
  177. *hap++ = bp;
  178. bp += n;
  179. cp += n;
  180. }
  181. if (hap > addrs || iquery_done) {
  182. *ap++ = NULL;
  183. *hap++ = NULL;
  184. if (data->state.nsort)
  185. qsort(addrs, hap - addrs, sizeof(struct in_addr), qcomp);
  186. if (SP(bp, char *, (hap - addrs) + (ap - aliases)) > buf + bufsize) {
  187. errno = ERANGE;
  188. return NULL;
  189. }
  190. result->h_addr_list = (char **) ALIGN(bp, char *);
  191. memcpy(result->h_addr_list, addrs, (hap - addrs) * sizeof(char *));
  192. result->h_aliases = result->h_addr_list + (hap - addrs);
  193. memcpy(result->h_aliases, aliases, (ap - aliases) * sizeof(char *));
  194. return result;
  195. } else {
  196. *errval = TRY_AGAIN;
  197. return NULL;
  198. }
  199. }
  200. /* Performs global initialization. */
  201. struct res_data *_res_init()
  202. {
  203. struct res_data *data;
  204. /* Make sure the global initializations have been done. */
  205. pthread_once(&init_once, _res_init_global);
  206. if (init_status < 0)
  207. return NULL;
  208. /* Initialize thread-specific data for this thread if it hasn't
  209.  * been done already. */
  210. data = (struct res_data *) pthread_getspecific(key);
  211. if (!data) {
  212. data = (struct res_data *) malloc(sizeof(struct res_data));
  213. if (data == NULL)
  214. return NULL;
  215. if (pthread_setspecific(key, data) < 0) {
  216. free(data);
  217. return NULL;
  218. }
  219. data->buf = NULL;
  220. data->state = start;
  221. data->errval = NO_RECOVERY;
  222. data->sock = -1;
  223. }
  224. return data;
  225. }
  226. static void _res_init_global()
  227. {
  228. int result;
  229. char line[BUFSIZ], buf[BUFSIZ], *domain, *p, *net;
  230. int i, localdomain_set = 0, num_servers = 0, num_sorts = 0;
  231. FILE *fp;
  232. struct in_addr addr;
  233. /* Assume an error state until we finish. */
  234. init_status = -1;
  235. /* Initialize the key for thread-specific data. */
  236. result = pthread_key_create(&key, free);
  237. if (result < 0)
  238. return;
  239. /* Initialize starting state. */
  240. start.retrans = RES_TIMEOUT;
  241. start.retry = DEFAULT_RETRIES;
  242. start.options = RES_DEFAULT;
  243. start.id = 0;
  244. start.nscount = 1;
  245. start.nsaddr.sin_addr.s_addr = INADDR_ANY;
  246. start.nsaddr.sin_family = AF_INET;
  247. start.nsaddr.sin_port = htons(NAMESERVER_PORT);
  248. start.nscount = 1;
  249. start.ndots = 1;
  250. start.pfcode = 0;
  251. strncpy(start.lookups, "f", sizeof(start.lookups));
  252. /* Look for a LOCALDOMAIN definition. */
  253. domain = getenv("LOCALDOMAIN");
  254. if (domain != NULL) {
  255. strncpy(start.defdname, domain, sizeof(start.defdname));
  256. domain = start.defdname;
  257. localdomain_set = 1;
  258. /* Construct a search path from the LOCALDOMAIN value, which is
  259.  * a space-separated list of strings.  For backwards-compatibility,
  260.  * a newline terminates the list. */
  261. i = 0;
  262. while (*domain && i < MAXDNSRCH) {
  263. start.dnsrch[i] = domain;
  264. while (*domain && !isspace(*domain))
  265. domain++;
  266. if (!*domain || *domain == 'n') {
  267. *domain = 0;
  268. break;
  269. }
  270. *domain++ = 0;
  271. while (isspace(*domain))
  272. domain++;
  273. i++;
  274. }
  275. }
  276. /* Look for a config file and read it in. */
  277. fp = fopen(_PATH_RESCONF, "r");
  278. if (fp != NULL) {
  279. strncpy(start.lookups, "bf", sizeof(start.lookups));
  280. /* Read in the configuration file. */
  281. while (fgets(line, sizeof(line), fp)) {
  282. /* Ignore blank lines and comments. */
  283. if (*line == ';' || *line == '#' || !*line)
  284. continue;
  285. if (strncmp(line, "domain", 6) == 0) {
  286. /* Read in the default domain, and initialize a one-
  287.  * element search path.  Skip the domain line if we
  288.  * already got one from the LOCALDOMAIN environment
  289.  * variable. */
  290. if (localdomain_set)
  291. continue;
  292. /* Look for the next word in the line. */
  293. p = line + 6;
  294. while (*p == ' ' || *p == 't')
  295. p++;
  296. if (!*p || *p == 'n')
  297. continue;
  298. /* Copy in the domain, and null-terminate it at the
  299.  * first tab or newline. */
  300. strncpy(start.defdname, p, sizeof(start.defdname) - 1);
  301. p = strpbrk(start.defdname, "tn");
  302. if (p)
  303. *p = 0;
  304. start.dnsrch[0] = start.defdname;
  305. start.dnsrch[1] = NULL;
  306. } else if (strncmp(line, "lookup", 6) == 0) {
  307. /* Get a list of lookup types. */
  308. memset(start.lookups, 0, sizeof(start.lookups));
  309. /* Find the next word in the line. */
  310. p = line + 6;
  311. while (isspace(*p))
  312. p++;
  313. i = 0;
  314. while (*p && i < MAXDNSLUS) {
  315. /* Add a lookup type. */
  316. if (*p == 'y' || *p == 'b' || *p == 'f')
  317. start.lookups[i++] = *p;
  318. /* Find the next word. */
  319. while (*p && !isspace(*p))
  320. p++;
  321. while (isspace(*p))
  322. p++;
  323. }
  324. } else if (strncmp(line, "search", 6) == 0) {
  325. /* Read in a space-separated list of domains to search
  326.  * when a name is not fully-qualified. Skip this line
  327.  * if the LOCALDOMAIN environment variable was set. */
  328. if (localdomain_set)
  329. continue;
  330. /* Look for the next word on the line. */
  331. p = line + 6;
  332. while (*p == ' ' || *p == 't')
  333. p++;
  334. if (!*p || *p == 'n')
  335. continue;
  336. /* Copy the rest of the line into start.defdname. */
  337. strncpy(start.defdname, p, sizeof(start.defdname) - 1);
  338. domain = start.defdname;
  339. p = strchr(domain, 'n');
  340. if (*p)
  341. *p = 0;
  342. /* Construct a search path from the line, which is a
  343.  * space-separated list of strings. */
  344. i = 0;
  345. while (*domain && i < MAXDNSRCH) {
  346. start.dnsrch[i] = domain;
  347. while (*domain && !isspace(*domain))
  348. domain++;
  349. if (!*domain || *domain == 'n') {
  350. *domain = 0;
  351. break;
  352. }
  353. *domain++ = 0;
  354. while (isspace(*domain))
  355. domain++;
  356. i++;
  357. }
  358. } else if (strncmp(line, "nameserver", 10) == 0) {
  359. /* Add an address to the list of name servers we can
  360.  * connect to. */
  361. /* Look for the next word in the line. */
  362. p = line + 10;
  363. while (*p == ' ' || *p == 't')
  364. p++;
  365. if (*p && *p != 'n' && inet_aton(p, &addr)) {
  366. start.nsaddr_list[num_servers].sin_addr = addr;
  367. start.nsaddr_list[num_servers].sin_family = AF_INET;
  368. start.nsaddr_list[num_servers].sin_port =
  369. htons(NAMESERVER_PORT);
  370. if (++num_servers >= MAXNS)
  371.     break;
  372. }
  373. } else if (strncmp(line, "sortlist", 8) == 0) {
  374. p = line + 8;
  375. while (num_sorts < MAXRESOLVSORT) {
  376. /* Find the next word in the line. */
  377. p = line + 8;
  378. while (*p == ' ' || *p == 't')
  379. p++;
  380. /* Read in an IP address and netmask. */
  381. if (sscanf(p, "%[0-9./]s", buf) != 1)
  382. break;
  383. net = strchr(buf, '/');
  384. if (net)
  385. *net = 0;
  386. /* Translate the address into an IP address
  387.  * and netmask. */
  388. if (inet_aton(buf, &addr)) {
  389. start.sort_list[num_sorts].addr = addr;
  390. if (net && inet_aton(net + 1, &addr)) {
  391. start.sort_list[num_sorts].mask = addr.s_addr;
  392. } else {
  393. start.sort_list[num_sorts].mask =
  394. net_mask(start.sort_list[num_sorts].addr);
  395. }
  396. num_sorts++;
  397. }
  398. /* Skip past this word. */
  399. if (net)
  400. *net = '/';
  401. p += strlen(buf);
  402. }
  403. }
  404. }
  405. fclose(fp);
  406. }
  407. /* If we don't have a default domain, strip off the first
  408.  * component of this machine's domain name, and make a one-
  409.  * element search path consisting of the default domain. */
  410. if (*start.defdname == 0) {
  411. if (gethostname(buf, sizeof(start.defdname) - 1) == 0) {
  412. p = strchr(buf, '.');
  413. if (p)
  414. strcpy(start.defdname, p + 1);
  415. }
  416. start.dnsrch[0] = start.defdname;
  417. start.dnsrch[1] = NULL;
  418. }
  419. p = getenv("RES_OPTIONS");
  420. if (p)
  421. set_options(p, "env");
  422. start.options |= RES_INIT;
  423. _res = start;
  424. init_status = 0;
  425. }
  426. static void set_options(const char *options, const char *source)
  427. {
  428. const char *p = options;
  429. int i;
  430. while (*p) {
  431. /* Skip leading and inner runs of spaces. */
  432. while (*p == ' ' || *p == 't')
  433. p++;
  434. /* Search for and process individual options. */
  435. if (strncmp(p, "ndots:", 6) == 0) {
  436. i = atoi(p + 6);
  437. start.ndots = (i <= RES_MAXNDOTS) ? i : RES_MAXNDOTS;
  438. } else if (!strncmp(p, "debug", 5))
  439.     start.options |= RES_DEBUG;
  440. else if (!strncmp(p, "usevc", 5))
  441.     start.options |= RES_USEVC;
  442. else if (!strncmp(p, "stayopen", 8))
  443.     start.options |= RES_STAYOPEN;
  444. /* Skip to next run of spaces */
  445. while (*p && *p != ' ' && *p != 't')
  446. p++;
  447. }
  448. }
  449. static pthread_ipaddr_type net_mask(struct in_addr in)
  450. {
  451. pthread_ipaddr_type i = ntohl(in.s_addr);
  452. if (IN_CLASSA(i))
  453. return htonl(IN_CLASSA_NET);
  454. if (IN_CLASSB(i))
  455. return htonl(IN_CLASSB_NET);
  456. return htonl(IN_CLASSC_NET);
  457. }
  458. /* Get the error value for this thread, or NO_RECOVERY if none has been
  459.  * successfully set.  The screw case to worry about here is if
  460.  * __res_init() fails for a resolver routine because it can't allocate
  461.  * or set the thread-specific data, and then __res_init() succeeds here.
  462.  * Because __res_init() sets errval to NO_RECOVERY after a successful
  463.  * initialization, we return NO_RECOVERY in that case, which is correct. */
  464. int _res_get_error()
  465. {
  466. struct res_data *data;
  467. data = _res_init();
  468. return (data) ? data->errval : NO_RECOVERY;
  469. }
  470. struct __res_state *_res_status()
  471. {
  472. struct res_data *data;
  473. data = _res_init();
  474. return (data) ? &data->state : NULL;
  475. }
  476. static int qcomp(const void *arg1, const void *arg2)
  477. {
  478. const struct in_addr **a1 = (const struct in_addr **) arg1;
  479. const struct in_addr **a2 = (const struct in_addr **) arg2;
  480. struct __res_state *state = _res_status();
  481. int pos1, pos2;
  482. for (pos1 = 0; pos1 < state->nsort; pos1++) {
  483. if (state->sort_list[pos1].addr.s_addr ==
  484. ((*a1)->s_addr & state->sort_list[pos1].mask))
  485. break;
  486. }
  487. for (pos2 = 0; pos2 < state->nsort; pos2++) {
  488. if (state->sort_list[pos2].addr.s_addr ==
  489. ((*a2)->s_addr & state->sort_list[pos2].mask))
  490. break;
  491. }
  492. return pos1 - pos2;
  493. }
  494. /*
  495.  * This routine is for closing the socket if a virtual circuit is used and
  496.  * the program wants to close it.  We don't use this routine, but libc
  497.  * might reference it.
  498.  *
  499.  * This routine is not expected to be user visible.
  500.  */
  501. void _res_close()
  502. {
  503. struct res_data *data;
  504. data = _res_init();
  505. if (data && data->sock != -1) {
  506. (void) close(data->sock);
  507. data->sock = -1;
  508. }
  509. }