1 /**
2  * net/resolver.h
3  * (c) 2005-2008 Murat Deligonul
4  */
5 
6 #ifndef __NET_RESOLVER_H
7 #define __NET_RESOLVER_H
8 
9 #include <vector>
10 #include <queue>
11 #include <sys/types.h>
12 #include <netdb.h>
13 #include <arpa/inet.h>
14 #include <netinet/in.h>
15 #include <pthread.h>
16 #include "debug.h"
17 
18 namespace net {
19 
20 class resolver_callback;
21 
22 class resolver {
23 public:
24 	/**
25 	 * Operational constants
26 	 */
27 	static const size_t MAX_HOSTLEN = NI_MAXHOST;
28 
29 	const unsigned int MAX_THREADS;
30 	const unsigned int MAX_LOOKUPS_PER_THREAD;
31 
32 
33 public:
34 	enum {
35 		OPT_NORMAL_LOOKUP  = 0,
36 		OPT_REVERSE_LOOKUP = 1,
37 	};
38 
39 	enum {
40 		SUCCESS = 0,
41 		ILLEGAL_REQUEST = -1,
42 	};
43 
44 
45 public:
46 	struct request {
47 		int 		id;		/* request id */
48 		int 		family;		/* family of address */
49 		int 		options;	/* other options */
50 
51 		union {
52 			int	iresult;	/* return value from resolution functions */
53 			unsigned short port;
54 		};
55 
56 		addrinfo 			* ai; 		/* raw result data */
57 		const resolver_callback 	* callback;	/* callback object pointer */
58 		char name[MAX_HOSTLEN];
59 
~requestrequest60 		~request() {
61 			if (ai != NULL) {
62 				freeaddrinfo(ai);
63 			}
64 		}
65 	};
66 	typedef struct request result;
67 
68 private:
69 	struct resolver_thread {
70 		pthread_t 	thread;
71 		resolver 	*self;
72 	};
73 
74 	static const struct resolver_thread 	default_rt;
75 
76 private:
77 	std::queue<request *> 	request_queue;
78 	std::vector<int>	cancelled_requests;
79 
80 	/* synchronization elements */
81 	pthread_mutex_t		queue_mutex;
82 	pthread_mutex_t		threads_mutex;
83 	pthread_cond_t		queue_cv;
84 
85 	int			fifo[2];
86 	int			current_id;
87 	unsigned 		active_threads;
88 	resolver_thread 	first_thread;
89 
90 
91 	static void * resolver_thread_fn(void *);
92 
93 public:
94 	resolver(unsigned int, unsigned int);
95 	~resolver();
96 
97 	/* asnyc. dns resolution methods */
98 	static request * create_request(int, const char *, unsigned short,
99 						int, const resolver_callback *);
100 	int 	async_lookup(request *);
101 	int 	cancel_async_lookup(int);
102 
async_lookup(int family,const char * hostname,unsigned short port,int options,const resolver_callback * callback)103 	int 	async_lookup(int family,
104 			const char * hostname, unsigned short port,
105 			int options, const resolver_callback * callback)
106 	{
107 		struct request * req = create_request(family, hostname, port, options, callback);
108 		return async_lookup(req);
109 	}
110 
111 	int 	process_results();
112 
113 	/* async. lookup result analysis */
114 	static char *	result_to_string(const request *, char *, size_t);
result_error(const request * req)115 	static const char *	result_error(const request * req) {
116 		return gai_strerror(req->iresult);
117 	}
118 
119 public:
120 	/* Low level resolution functions */
121 	static int resolve_address(int, int, const char *, unsigned short, struct addrinfo **);
122 	static int lookup(const char *, char * , size_t);
123 	static int reverse_lookup(const char *, char * , size_t);
124 	static int test_bind(const char *, unsigned short);
125 	static int raw_to_ip(const struct sockaddr *, size_t, char *, size_t, unsigned short * = NULL);
126 	static int ip_to_raw(const char *, unsigned short, struct sockaddr *, size_t);
127 	static bool is_ip_address(int, const char *);
128 
129 private:
fifo_reader_fd()130 	int 	fifo_reader_fd() const {
131 		return fifo[0];
132 	}
fifo_writer_fd()133 	int	fifo_writer_fd() const {
134 		return fifo[1];
135 	}
136 
137 	int	process_request(request *);
138 	int	write_result(const request *);
139 	request * read_result();
140 	int 	process_result(request *);
141 
142 	friend class radaptor;
143 
144 private:
145 	// non-copyable
146 	resolver(const resolver&);
147 	resolver& operator=(const resolver&);
148 };
149 
150 /**
151   * Interface for resolver callback
152   */
153 class resolver_callback {
154 public:
155 	virtual int async_lookup_finished(const resolver::result *) const = 0;
156 	virtual int async_lookup_failed(const resolver::result *) const = 0;
~resolver_callback()157 	virtual ~resolver_callback() {}
158 };
159 
160 /**
161   * Class template to wrap class member functions into a resolver callback;
162   * avoids having to use inheritance.
163   */
164 
165 template<class T,
166 	 int (T::*finished_fn)(const resolver::result *),
167 	 int (T::*failed_fn)(const resolver::result *)>
168 	 	class resolver_callback_wrapper : public resolver_callback {
169 private:
170 	T * const instance;
171 
172 public:
resolver_callback_wrapper(T * t)173 	resolver_callback_wrapper(T * t) : instance(t) { }
async_lookup_finished(const resolver::result * r)174 	virtual int async_lookup_finished(const resolver::result * r) const {
175 		return (instance->*finished_fn)(r);
176 	}
177 
async_lookup_failed(const resolver::result * r)178 	virtual int async_lookup_failed(const resolver::result * r) const {
179 		return (instance->*failed_fn)(r);
180 	}
181 };
182 
183 }  /* namespace net */
184 #endif /* __NET_RESOLVER_H */
185