PageRenderTime 54ms CodeModel.GetById 14ms app.highlight 34ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llmessage/llares.h

https://bitbucket.org/lindenlab/viewer-beta/
C++ Header | 582 lines | 234 code | 88 blank | 260 comment | 1 complexity | 63abdc8393fba28e1c39a43e65fbf958 MD5 | raw file
  1/** 
  2 * @file llares.h
  3 * @author Bryan O'Sullivan
  4 * @date 2007-08-15
  5 * @brief Wrapper for asynchronous DNS lookups.
  6 *
  7 * $LicenseInfo:firstyear=2007&license=viewerlgpl$
  8 * Second Life Viewer Source Code
  9 * Copyright (C) 2010, Linden Research, Inc.
 10 * 
 11 * This library is free software; you can redistribute it and/or
 12 * modify it under the terms of the GNU Lesser General Public
 13 * License as published by the Free Software Foundation;
 14 * version 2.1 of the License only.
 15 * 
 16 * This library is distributed in the hope that it will be useful,
 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 19 * Lesser General Public License for more details.
 20 * 
 21 * You should have received a copy of the GNU Lesser General Public
 22 * License along with this library; if not, write to the Free Software
 23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 24 * 
 25 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 26 * $/LicenseInfo$
 27 */
 28
 29#ifndef LL_LLARES_H
 30#define LL_LLARES_H
 31
 32#ifdef LL_WINDOWS
 33// ares.h is broken on windows in that it depends on types defined in ws2tcpip.h
 34// we need to include them first to work around it, but the headers issue warnings
 35# pragma warning(push)
 36# pragma warning(disable:4996)
 37# include <winsock2.h>
 38# include <ws2tcpip.h>
 39# pragma warning(pop)
 40#endif
 41
 42#ifdef LL_STANDALONE
 43# include <ares.h>
 44#else
 45# include <ares/ares.h>
 46#endif
 47
 48#include "llpointer.h"
 49#include "llrefcount.h"
 50#include "lluri.h"
 51
 52#include <boost/shared_ptr.hpp>
 53
 54class LLQueryResponder;
 55class LLAresListener;
 56
 57/**
 58 * @brief Supported DNS RR types.
 59 */
 60enum LLResType
 61{
 62	RES_INVALID = 0,			/**< Cookie. */
 63	RES_A = 1,					/**< "A" record. IPv4 address. */
 64	RES_NS = 2,					/**< "NS" record. Authoritative server. */
 65	RES_CNAME = 5,				/**< "CNAME" record. Canonical name. */
 66	RES_PTR = 12,				/**< "PTR" record. Domain name pointer. */
 67	RES_AAAA = 28,				/**< "AAAA" record. IPv6 Address. */
 68	RES_SRV = 33,				/**< "SRV" record. Server Selection. */
 69	RES_MAX = 65536				/**< Sentinel; RR types are 16 bits wide. */
 70};
 71
 72/**
 73 * @class LLDnsRecord
 74 * @brief Base class for all DNS RR types.
 75 */
 76class LLDnsRecord : public LLRefCount
 77{
 78protected:
 79	friend class LLQueryResponder;
 80
 81	LLResType mType;
 82	std::string mName;
 83	unsigned mTTL;
 84	
 85	virtual int parse(const char *buf, size_t len, const char *pos,
 86					  size_t rrlen) = 0;
 87
 88	LLDnsRecord(LLResType type, const std::string &name, unsigned ttl);
 89	
 90public:
 91	/**
 92	 * @brief Record name.
 93	 */
 94	const std::string &name() const { return mName; }
 95
 96	/**
 97	 * @brief Time-to-live value, in seconds.
 98	 */
 99	unsigned ttl() const { return mTTL; }
100
101	/**
102	 * @brief RR type.
103	 */
104	LLResType type() const { return mType; }
105};
106
107/**
108 * @class LLAddrRecord
109 * @brief Base class for address-related RRs.
110 */
111class LLAddrRecord : public LLDnsRecord
112{
113protected:
114	friend class LLQueryResponder;
115
116	LLAddrRecord(LLResType type, const std::string &name, unsigned ttl);
117
118	union 
119	{
120		sockaddr sa;
121		sockaddr_in sin;
122		sockaddr_in6 sin6;
123	} mSA;
124
125	socklen_t mSize;
126
127public:
128	/**
129	 * @brief Generic socket address.
130	 */
131	const sockaddr &addr() const { return mSA.sa; }
132
133	/**
134	 * @brief Size of the socket structure.
135	 */
136	socklen_t size() const { return mSize; }
137};
138
139/**
140 * @class LLARecord
141 * @brief A RR, for IPv4 addresses.
142 */
143class LLARecord : public LLAddrRecord
144{
145protected:
146	friend class LLQueryResponder;
147
148	LLARecord(const std::string &name, unsigned ttl);
149
150	int parse(const char *buf, size_t len, const char *pos, size_t rrlen);
151
152public:
153	/**
154	 * @brief Socket address.
155	 */
156	const sockaddr_in &addr_in() const { return mSA.sin; }
157};
158
159/**
160 * @class LLAaaaRecord
161 * @brief AAAA RR, for IPv6 addresses.
162 */
163class LLAaaaRecord : public LLAddrRecord
164{
165protected:
166	friend class LLQueryResponder;
167
168	LLAaaaRecord(const std::string &name, unsigned ttl);
169
170	int parse(const char *buf, size_t len, const char *pos, size_t rrlen);
171
172public:
173	/**
174	 * @brief Socket address.
175	 */
176	const sockaddr_in6 &addr_in6() const { return mSA.sin6; }
177};
178	
179/**
180 * @class LLHostRecord
181 * @brief Base class for host-related RRs.
182 */
183class LLHostRecord : public LLDnsRecord
184{
185protected:
186	LLHostRecord(LLResType type, const std::string &name, unsigned ttl);
187
188	int parse(const char *buf, size_t len, const char *pos, size_t rrlen);
189
190	std::string mHost;
191
192public:
193	/**
194	 * @brief Host name.
195	 */
196	const std::string &host() const { return mHost; }
197};
198	
199/**
200 * @class LLCnameRecord
201 * @brief CNAME RR.
202 */
203class LLCnameRecord : public LLHostRecord
204{
205protected:
206	friend class LLQueryResponder;
207
208	LLCnameRecord(const std::string &name, unsigned ttl);
209};
210	
211/**
212 * @class LLPtrRecord
213 * @brief PTR RR.
214 */
215class LLPtrRecord : public LLHostRecord
216{
217protected:
218	friend class LLQueryResponder;
219
220	LLPtrRecord(const std::string &name, unsigned ttl);
221};
222
223/**
224 * @class LLSrvRecord
225 * @brief SRV RR.
226 */
227class LLSrvRecord : public LLHostRecord
228{
229protected:
230	U16 mPriority;
231	U16 mWeight;
232	U16 mPort;
233
234	int parse(const char *buf, size_t len, const char *pos, size_t rrlen);
235
236public:
237	LLSrvRecord(const std::string &name, unsigned ttl);
238
239	/**
240	 * @brief Service priority.
241	 */
242	U16 priority() const { return mPriority; }
243
244	/**
245	 * @brief Service weight.
246	 */
247	U16 weight() const { return mWeight; }
248
249	/**
250	 * @brief Port number of service.
251	 */
252	U16 port() const { return mPort; }
253
254	/**
255	 * @brief Functor for sorting SRV records by priority.
256	 */
257	struct ComparePriorityLowest
258	{
259		bool operator()(const LLSrvRecord& lhs, const LLSrvRecord& rhs)
260		{
261			return lhs.mPriority < rhs.mPriority;
262		}
263	};
264};
265	
266/**
267 * @class LLNsRecord
268 * @brief NS RR.
269 */
270class LLNsRecord : public LLHostRecord
271{
272public:
273	LLNsRecord(const std::string &name, unsigned ttl);
274};
275
276class LLQueryResponder;
277
278/**
279 * @class LLAres
280 * @brief Asynchronous address resolver.
281 */
282class LLAres
283{
284public:
285    /**
286	 * @class HostResponder
287	 * @brief Base class for responding to hostname lookups.
288	 * @see LLAres::getHostByName
289	 */
290	class HostResponder : public LLRefCount
291	{
292	public:
293		virtual ~HostResponder();
294
295		virtual void hostResult(const hostent *ent);
296		virtual void hostError(int code);
297	};
298
299    /**
300	 * @class NameInfoResponder
301	 * @brief Base class for responding to address lookups.
302	 * @see LLAres::getNameInfo
303	 */
304	class NameInfoResponder : public LLRefCount
305	{
306	public:
307		virtual ~NameInfoResponder();
308
309		virtual void nameInfoResult(const char *node, const char *service);
310		virtual void nameInfoError(int code);
311	};
312
313    /**
314	 * @class QueryResponder
315	 * @brief Base class for responding to custom searches.
316	 * @see LLAres::search
317	 */
318	class QueryResponder : public LLRefCount
319	{
320	public:
321		virtual ~QueryResponder();
322
323		virtual void queryResult(const char *buf, size_t len);
324		virtual void queryError(int code);
325	};
326
327	class SrvResponder;
328	class UriRewriteResponder;
329		
330	LLAres();
331
332	~LLAres();
333
334	/**
335	 * Cancel all outstanding requests.  The error methods of the
336	 * corresponding responders will be called, with ARES_ETIMEOUT.
337	 */
338	void cancel();
339	
340	/**
341	 * Look up the address of a host.
342	 *
343	 * @param name name of host to look up
344	 * @param resp responder to call with result
345	 * @param family AF_INET for IPv4 addresses, AF_INET6 for IPv6
346	 */
347	void getHostByName(const std::string &name, HostResponder *resp,
348					   int family = AF_INET) {
349		getHostByName(name.c_str(), resp, family);
350	}
351
352	/**
353	 * Look up the address of a host.
354	 *
355	 * @param name name of host to look up
356	 * @param resp responder to call with result
357	 * @param family AF_INET for IPv4 addresses, AF_INET6 for IPv6
358	 */
359	void getHostByName(const char *name, HostResponder *resp,
360					   int family = PF_INET);
361
362	/**
363	 * Look up the name associated with a socket address.
364	 *
365	 * @param sa socket address to look up
366	 * @param salen size of socket address
367	 * @param flags flags to use
368	 * @param resp responder to call with result
369	 */
370	void getNameInfo(const struct sockaddr &sa, socklen_t salen, int flags,
371					 NameInfoResponder *resp);
372
373	/**
374	 * Look up SRV (service location) records for a service name.
375	 *
376	 * @param name service name (e.g. "_https._tcp.login.agni.lindenlab.com")
377	 * @param resp responder to call with result
378	 */
379	void getSrvRecords(const std::string &name, SrvResponder *resp);
380
381	/**
382	 * Rewrite a URI, using SRV (service location) records for its
383	 * protocol if available.  If no SRV records are published, the
384	 * existing URI is handed to the responder.
385	 *
386	 * @param uri URI to rewrite
387	 * @param resp responder to call with result
388	 */
389	void rewriteURI(const std::string &uri,
390					UriRewriteResponder *resp);
391
392	/**
393	 * Start a custom search.
394	 *
395	 * @param query query to make
396	 * @param type type of query to perform
397	 * @param resp responder to call with result
398	 */
399	void search(const std::string &query, LLResType type,
400				QueryResponder *resp);
401
402	/**
403	 * Process any outstanding queries.  This method takes an optional
404	 * timeout parameter (specified in microseconds).  If provided, it
405	 * will block the calling thread for that length of time to await
406	 * possible responses. A timeout of zero will return immediately
407	 * if there are no responses or timeouts to process.
408	 *
409	 * @param timeoutUsecs number of microseconds to block before timing out
410	 * @return whether any responses were processed
411	 */
412	bool process(U64 timeoutUsecs = 0);
413
414	/**
415	 * Process all outstanding queries, blocking the calling thread
416	 * until all have either been responded to or timed out.
417	 *
418	 * @return whether any responses were processed
419	 */
420	bool processAll();
421	
422	/**
423	 * Expand a DNS-encoded compressed string into a normal string.
424	 *
425	 * @param encoded the encoded name (null-terminated)
426	 * @param abuf the response buffer in which the string is embedded
427	 * @param alen the length of the response buffer
428	 * @param s the string into which to place the result
429	 * @return ARES_SUCCESS on success, otherwise an error indicator
430	 */
431	static int expandName(const char *encoded, const char *abuf, size_t alen,
432						  std::string &s) {
433		size_t ignore;
434		return expandName(encoded, abuf, alen, s, ignore);
435	}
436	
437	static int expandName(const char *encoded, const char *abuf, size_t alen,
438						  std::string &s, size_t &enclen);
439
440	/**
441	 * Return a string describing an error code.
442	 */
443	static const char *strerror(int code);
444
445	bool isInitialized(void) { return mInitSuccess; }
446
447protected:
448	ares_channel chan_;
449	bool mInitSuccess;
450    // boost::scoped_ptr would actually fit the requirement better, but it
451    // can't handle incomplete types as boost::shared_ptr can.
452    boost::shared_ptr<LLAresListener> mListener;
453};
454	
455/**
456 * An ordered collection of DNS resource records.
457 */
458typedef std::vector<LLPointer<LLDnsRecord> > dns_rrs_t;
459
460/**
461 * @class LLQueryResponder
462 * @brief Base class for friendly handling of DNS query responses.
463 *
464 * This class parses a DNS response and represents it in a friendly
465 * manner.
466 *
467 * @see LLDnsRecord
468 * @see LLARecord
469 * @see LLNsRecord
470 * @see LLCnameRecord
471 * @see LLPtrRecord
472 * @see LLAaaaRecord
473 * @see LLSrvRecord
474 */
475class LLQueryResponder : public LLAres::QueryResponder
476{
477protected:
478	int mResult;
479	std::string mQuery;
480	LLResType mType;
481	
482	dns_rrs_t mAnswers;
483	dns_rrs_t mAuthorities;
484	dns_rrs_t mAdditional;
485
486	/**
487	 * Parse a single RR.
488	 */
489	int parseRR(const char *buf, size_t len, const char *&pos,
490				LLPointer<LLDnsRecord> &r);
491	/**
492	 * Parse one section of a response.
493	 */
494	int parseSection(const char *buf, size_t len,
495					 size_t count, const char *& pos, dns_rrs_t &rrs);
496
497	void queryResult(const char *buf, size_t len);
498	virtual void querySuccess();
499
500public:
501	LLQueryResponder();
502
503	/**
504	 * Indicate whether the response could be parsed successfully.
505	 */
506	bool valid() const { return mResult == ARES_SUCCESS; }
507
508	/**
509	 * The more detailed result of parsing the response.
510	 */
511	int result() const { return mResult; }
512	
513	/**
514	 * Return the query embedded in the response.
515	 */
516	const std::string &query() const { return mQuery; }
517
518	/**
519	 * Return the contents of the "answers" section of the response.
520	 */
521	const dns_rrs_t &answers() const { return mAnswers; }
522
523	/**
524	 * Return the contents of the "authorities" section of the
525	 * response.
526	 */
527	const dns_rrs_t &authorities() const { return mAuthorities; }
528
529	/**
530	 * Return the contents of the "additional records" section of the
531	 * response.
532	 */
533	const dns_rrs_t &additional() const { return mAdditional; }
534};
535
536/**
537 * @class LLAres::SrvResponder
538 * @brief Class for handling SRV query responses.
539 */
540class LLAres::SrvResponder : public LLQueryResponder
541{
542public:
543	friend void LLAres::getSrvRecords(const std::string &name,
544									  SrvResponder *resp);
545	void querySuccess();
546	void queryError(int code);
547
548	virtual void srvResult(const dns_rrs_t &ents);
549	virtual void srvError(int code);
550};
551
552/**
553 * @class LLAres::UriRewriteResponder
554 * @brief Class for handling URI rewrites based on SRV records.
555 */
556class LLAres::UriRewriteResponder : public LLQueryResponder
557{
558protected:
559	LLURI mUri;
560
561public:
562	friend void LLAres::rewriteURI(const std::string &uri,
563								   UriRewriteResponder *resp);
564	void querySuccess();
565	void queryError(int code);
566
567	virtual void rewriteResult(const std::vector<std::string> &uris);
568};
569	
570/**
571 * Singleton responder.
572 */
573extern LLAres *gAres;
574
575/**
576 * Set up the singleton responder.  It's safe to call this more than
577 * once from within a single thread, but this function is not
578 * thread safe.
579 */
580extern LLAres *ll_init_ares();
581
582#endif // LL_LLARES_H