⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dns.c

📁 一个很有名的浏览器
💻 C
字号:
/* Domain Name System Resolver Department *//* $Id: dns.c,v 1.53.2.4 2005/05/01 21:15:32 jonas Exp $ */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <stdlib.h>#include <string.h>#include <sys/types.h>#ifdef HAVE_NETDB_H#include <netdb.h> /* OS/2 needs this after sys/types.h */#endif#ifdef HAVE_SYS_SOCKET_H#include <sys/socket.h> /* OS/2 needs this after sys/types.h */#endif#ifdef HAVE_FCNTL_H#include <fcntl.h> /* OS/2 needs this after sys/types.h */#endif#ifdef HAVE_UNISTD_H#include <unistd.h>#endif/* Go and say 'thanks' to BSD. */#ifdef HAVE_NETINET_IN_H#include <netinet/in.h>#endif#ifdef HAVE_ARPA_INET_H#include <arpa/inet.h>#endif#include "elinks.h"#include "config/options.h"#include "lowlevel/dns.h"#include "lowlevel/select.h"#include "osdep/osdep.h"#include "util/error.h"#include "util/memory.h"#include "util/ttime.h"struct dnsentry {	LIST_HEAD(struct dnsentry);	struct sockaddr_storage *addr; /* pointer to array of addresses */	ttime get_time;	int addrno; /* array len / sizeof(sockaddr_storage) */	unsigned char name[1]; /* Must be last */};struct dnsquery {#ifdef THREAD_SAFE_LOOKUP	struct dnsquery *next_in_queue;#endif	void (*fn)(void *, int);	void *data;	void (*xfn)(struct dnsquery *, int);	struct dnsquery **s;	/* addr and addrno lifespan exceeds life of this structure, the caller	 * holds memory being pointed upon be these functions. Thus, when	 * free()ing, *always* set pointer to NULL ! */	struct sockaddr_storage **addr; /* addr of pointer to array of addresses */	int *addrno; /* array len / sizeof(sockaddr_storage) */	int h;	unsigned char name[1]; /* Must be last */};#ifdef THREAD_SAFE_LOOKUPstatic struct dnsquery *dns_queue = NULL;#endifINIT_LIST_HEAD(dns_cache);intdo_real_lookup(unsigned char *name, struct sockaddr_storage **addrs, int *addrno,	       int in_thread){#ifdef CONFIG_IPV6	struct addrinfo hint, *ai, *ai_cur;#else	struct hostent *hostent;#endif	int i;	if (!name || !addrs || !addrno)		return -1;#ifdef CONFIG_IPV6	/* I had a strong preference for the following, but the glibc is really	 * obsolete so I had to rather use much more complicated getaddrinfo().	 * But we duplicate the code terribly here :|. */	/* hostent = getipnodebyname(name, AF_INET6, AI_ALL | AI_ADDRCONFIG, NULL); */	memset(&hint, 0, sizeof(hint));	hint.ai_family = AF_UNSPEC;	hint.ai_socktype = SOCK_STREAM;	if (getaddrinfo(name, NULL, &hint, &ai) != 0) return -1;#else	/* Seems there are problems on Mac, so we first need to try	 * gethostbyaddr(). */#ifdef HAVE_GETHOSTBYADDR	hostent = gethostbyaddr(name, strlen(name), AF_INET);	if (!hostent)#endif	{		hostent = gethostbyname(name);		if (!hostent) return -1;	}#endif#ifdef CONFIG_IPV6	for (i = 0, ai_cur = ai; ai_cur; i++, ai_cur = ai_cur->ai_next);#else	for (i = 0; hostent->h_addr_list[i] != NULL; i++);#endif	/* We cannot use mem_*() in thread ("It will chew memory on OS/2 and	 * BeOS because there are no locks around the memory debugging code."	 * -- Mikulas).  So we don't if in_thread != 0. */	*addrs = in_thread ? calloc(i, sizeof(**addrs))			   : mem_calloc(i, sizeof(**addrs));	if (!*addrs) return -1;	*addrno = i;#ifdef CONFIG_IPV6	for (i = 0, ai_cur = ai; ai_cur; i++, ai_cur = ai_cur->ai_next) {		struct sockaddr_in6 *addr = (struct sockaddr_in6 *) &(*addrs)[i];		memcpy(addr, ai_cur->ai_addr, ai_cur->ai_addrlen);	}	freeaddrinfo(ai);#else	for (i = 0; hostent->h_addr_list[i] != NULL; i++) {		struct sockaddr_in *addr = (struct sockaddr_in *) &(*addrs)[i];		addr->sin_family = hostent->h_addrtype;		memcpy(&addr->sin_addr.s_addr, hostent->h_addr_list[i], hostent->h_length);	}#endif	return 0;}#ifndef NO_ASYNC_LOOKUPstatic voidlookup_fn(void *data, int h){	unsigned char *name = (unsigned char *) data;	struct sockaddr_storage *addrs;	int addrno, i, done, todo;	if (do_real_lookup(name, &addrs, &addrno, 1) < 0) return;	/* We will do blocking I/O here, however it's only local communication	 * and it's supposed to be just a flash talk, so it shouldn't matter.	 * And it would be incredibly more complicated and messy (and mainly	 * useless) to do this in non-blocking way. */	if (set_blocking_fd(h) < 0) return;	todo = sizeof(addrno);	done = 0;	do {		int w = safe_write(h, &addrno + done, todo - done);		if (w < 0) return;		done += w;	} while (done < todo);	assert(done == todo);	for (i = 0; i < addrno; i++) {		struct sockaddr_storage *addr = &addrs[i];		todo = sizeof(*addr);		done = 0;		do {			int w = safe_write(h, addr + done, todo - done);			if (w < 0) return;			done += w;		} while (done < todo);		assert(done == todo);	}	/* We're in thread, thus we must do plain free(). */	free(addrs);}#endif#ifndef NO_ASYNC_LOOKUPstatic voidend_real_lookup(void *data){	struct dnsquery *query = (struct dnsquery *) data;	int res = -1;	int i, done, todo;	if (!query->addr || !query->addrno) goto done;	*query->addr = NULL; /* XXX: is this correct ?? --Zas */	/* We will do blocking I/O here, however it's only local communication	 * and it's supposed to be just a flash talk, so it shouldn't matter.	 * And it would be incredibly more complicated and messy (and mainly	 * useless) to do this in non-blocking way. */	if (set_blocking_fd(query->h) < 0) goto done;	todo = sizeof(*query->addrno);	done = 0;	do {		int r = safe_read(query->h, query->addrno + done, todo - done);		if (r <= 0) goto done;		done += r;	} while (done < todo);	assert(done == todo);	*query->addr = mem_calloc(*query->addrno, sizeof(**query->addr));	if (!*query->addr) goto done;	for (i = 0; i < *query->addrno; i++) {		struct sockaddr_storage *addr = &(*query->addr)[i];		todo = sizeof(*addr);		done = 0;		do {			int r = safe_read(query->h, addr + done, todo - done);			if (r <= 0) goto done;			done += r;		} while (done < todo);		assert(done == todo);	}	res = 0;done:	if (res < 0 && query->addr) mem_free_set(&*query->addr, NULL);	clear_handlers(query->h);	close(query->h);	query->xfn(query, res);}#endifstatic voidfailed_real_lookup(void *data){	struct dnsquery *query = (struct dnsquery *) data;	clear_handlers(query->h);	close(query->h);	query->xfn(query, -1);}static intdo_lookup(struct dnsquery *query, int force_async){	int res;	/* DBG("starting lookup for %s", query->name); */#ifndef NO_ASYNC_LOOKUP	if (force_async || get_opt_bool("connection.async_dns")) {		query->h = start_thread(lookup_fn, query->name,					strlen(query->name) + 1);		if (query->h != -1) {			/* async lookup */			set_handlers(query->h, end_real_lookup, NULL,				     failed_real_lookup, query);			return 1;		}	}#endif	/* sync lookup */	res = do_real_lookup(query->name, query->addr, query->addrno, 0);	query->xfn(query, res);	return 0;}static intdo_queued_lookup(struct dnsquery *query){#ifdef THREAD_SAFE_LOOKUP	query->next_in_queue = NULL;	if (!dns_queue) {		dns_queue = query;		/* DBG("direct lookup"); */		return do_lookup(query, 0);	} else {		/* DBG("queuing lookup for %s", q->name); */		assertm(!dns_queue->next_in_queue, "DNS queue corrupted");		dns_queue->next_in_queue = query;		dns_queue = query;		return -1;	}#else	return do_lookup(query, 0);#endif}static intfind_in_dns_cache(unsigned char *name, struct dnsentry **dnsentry){	struct dnsentry *e;	foreach (e, dns_cache)		if (!strcasecmp(e->name, name)) {			del_from_list(e);			add_to_list(dns_cache, e);			*dnsentry = e;			return 0;		}	return -1;}static voidend_dns_lookup(struct dnsquery *query, int res){	struct dnsentry *dnsentry;	void (*fn)(void *, int);	void *data;	int namelen;	/* DBG("end lookup %s (%d)", query->name, res); */#ifdef THREAD_SAFE_LOOKUP	if (query->next_in_queue) {		/* DBG("processing next in queue: %s", query->next_in_queue->name); */		do_lookup(query->next_in_queue, 1);	} else {	       	dns_queue = NULL;	}#endif	if (!query->fn || !query->addr) {		if (query->addr) mem_free_set(&*query->addr, NULL);		mem_free(query);		return;	}	if (find_in_dns_cache(query->name, &dnsentry) >= 0) {		assert(dnsentry);		if (res < 0) {			int size;			/* query->addr(no) is pointer to something already allocated */			assert(dnsentry->addrno > 0);			size = dnsentry->addrno * sizeof(**query->addr);			*query->addr = mem_alloc(size);			if (!*query->addr) goto done;			memcpy(*query->addr, dnsentry->addr, size);			*query->addrno = dnsentry->addrno;			res = 0;			goto done;		}		del_from_list(dnsentry);		mem_free(dnsentry->addr);		mem_free(dnsentry);	}	if (res < 0) goto done;	namelen = strlen(query->name);	dnsentry = mem_calloc(1, sizeof(*dnsentry) + namelen);	if (dnsentry) {		int size;		memcpy(dnsentry->name, query->name, namelen); /* calloc() sets nul char for us. */		assert(*query->addrno > 0);		size = *query->addrno * sizeof(*dnsentry->addr);		dnsentry->addr = mem_alloc(size);		if (!dnsentry->addr) goto done;		memcpy(dnsentry->addr, *query->addr, size);;		dnsentry->addrno = *query->addrno;		dnsentry->get_time = get_time();		add_to_list(dns_cache, dnsentry);	}done:	fn = query->fn;	data = query->data;	if (query->s) *query->s = NULL;	/* query->addr is freed later by dns_found() */	mem_free(query);	fn(data, res);}intfind_host_no_cache(unsigned char *name, struct sockaddr_storage **addr, int *addrno,		   void **query_p, void (*fn)(void *, int), void *data){	struct dnsquery *query;	int namelen = strlen(name);	query = mem_calloc(1, sizeof(*query) + namelen);	if (!query) {		fn(data, -1);		return 0;	}	query->fn = fn;	query->data = data;	query->s = (struct dnsquery **) query_p;	query->addr = addr;	query->addrno = addrno;	memcpy(query->name, name, namelen); /* calloc() sets nul char for us. */	if (query_p) *((struct dnsquery **) query_p) = query;	query->xfn = end_dns_lookup;	return do_queued_lookup(query);}intfind_host(unsigned char *name, struct sockaddr_storage **addr, int *addrno,	  void **query_p, void (*fn)(void *, int), void *data){	struct dnsentry *dnsentry;	if (query_p) *query_p = NULL;	if (find_in_dns_cache(name, &dnsentry) >= 0) {		assert(dnsentry && dnsentry->addrno > 0);		if (dnsentry->get_time + DNS_TIMEOUT >= get_time()) {			int size = sizeof(**addr) * dnsentry->addrno;			*addr = mem_alloc(size);			if (*addr) {				memcpy(*addr, dnsentry->addr, size);				*addrno = dnsentry->addrno;				fn(data, 0);			}			return 0;		}	}	return find_host_no_cache(name, addr, addrno, query_p, fn, data);}voidkill_dns_request(void **qp){	struct dnsquery *query = *qp;	query->fn = NULL;	failed_real_lookup(query);	*qp = NULL;}static voiddel_dns_cache_entry(struct dnsentry **d){	struct dnsentry *e = *d;	*d = (*d)->prev;	del_from_list(e);	mem_free_if(e->addr);	mem_free(e);}voidshrink_dns_cache(int whole){	struct dnsentry *d;	if (whole) {		foreach (d, dns_cache)			del_dns_cache_entry(&d);	} else {		ttime oldest = get_time() - DNS_TIMEOUT;		foreach (d, dns_cache)			if (d->get_time < oldest)				del_dns_cache_entry(&d);	}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -