diff options
author | Bryan O'Sullivan <bos@lindenlab.com> | 2008-06-02 21:14:31 +0000 |
---|---|---|
committer | Bryan O'Sullivan <bos@lindenlab.com> | 2008-06-02 21:14:31 +0000 |
commit | 9db949eec327df4173fde3de934a87bedb0db13c (patch) | |
tree | aeffa0f0e68b1d2ceb74d460cbbd22652c9cd159 /indra/llmessage/llares.h | |
parent | 419e13d0acaabf5e1e02e9b64a07648bce822b2f (diff) |
svn merge -r88066:88786 svn+ssh://svn.lindenlab.com/svn/linden/branches/cmake-9-merge
dataserver-is-deprecated
for-fucks-sake-whats-with-these-commit-markers
Diffstat (limited to 'indra/llmessage/llares.h')
-rw-r--r-- | indra/llmessage/llares.h | 572 |
1 files changed, 572 insertions, 0 deletions
diff --git a/indra/llmessage/llares.h b/indra/llmessage/llares.h new file mode 100644 index 0000000000..4dd65600cc --- /dev/null +++ b/indra/llmessage/llares.h @@ -0,0 +1,572 @@ +/** + * @file llares.h + * @author Bryan O'Sullivan + * @date 2007-08-15 + * @brief Wrapper for asynchronous DNS lookups. + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLARES_H +#define LL_LLARES_H + +#ifdef LL_WINDOWS +# include <ws2tcpip.h> +#endif + +#ifdef LL_STANDALONE +# include <ares.h> +#else +# include <ares/ares.h> +#endif + +#include "llmemory.h" +#include "lluri.h" + +class LLQueryResponder; + +/** + * @brief Supported DNS RR types. + */ +enum LLResType +{ + RES_INVALID = 0, /**< Cookie. */ + RES_A = 1, /**< "A" record. IPv4 address. */ + RES_NS = 2, /**< "NS" record. Authoritative server. */ + RES_CNAME = 5, /**< "CNAME" record. Canonical name. */ + RES_PTR = 12, /**< "PTR" record. Domain name pointer. */ + RES_AAAA = 28, /**< "AAAA" record. IPv6 Address. */ + RES_SRV = 33, /**< "SRV" record. Server Selection. */ + RES_MAX = 65536 /**< Sentinel; RR types are 16 bits wide. */ +}; + +/** + * @class LLDnsRecord + * @brief Base class for all DNS RR types. + */ +class LLDnsRecord : public LLRefCount +{ +protected: + friend class LLQueryResponder; + + LLResType mType; + std::string mName; + unsigned mTTL; + + virtual int parse(const char *buf, size_t len, const char *pos, + size_t rrlen) = 0; + + LLDnsRecord(LLResType type, const std::string &name, unsigned ttl); + +public: + /** + * @brief Record name. + */ + const std::string &name() const { return mName; } + + /** + * @brief Time-to-live value, in seconds. + */ + unsigned ttl() const { return mTTL; } + + /** + * @brief RR type. + */ + LLResType type() const { return mType; } +}; + +/** + * @class LLAddrRecord + * @brief Base class for address-related RRs. + */ +class LLAddrRecord : public LLDnsRecord +{ +protected: + friend class LLQueryResponder; + + LLAddrRecord(LLResType type, const std::string &name, unsigned ttl); + + union + { + sockaddr sa; + sockaddr_in sin; + sockaddr_in6 sin6; + } mSA; + + socklen_t mSize; + +public: + /** + * @brief Generic socket address. + */ + const sockaddr &addr() const { return mSA.sa; } + + /** + * @brief Size of the socket structure. + */ + socklen_t size() const { return mSize; } +}; + +/** + * @class LLARecord + * @brief A RR, for IPv4 addresses. + */ +class LLARecord : public LLAddrRecord +{ +protected: + friend class LLQueryResponder; + + LLARecord(const std::string &name, unsigned ttl); + + int parse(const char *buf, size_t len, const char *pos, size_t rrlen); + +public: + /** + * @brief Socket address. + */ + const sockaddr_in &addr_in() const { return mSA.sin; } +}; + +/** + * @class LLAaaaRecord + * @brief AAAA RR, for IPv6 addresses. + */ +class LLAaaaRecord : public LLAddrRecord +{ +protected: + friend class LLQueryResponder; + + LLAaaaRecord(const std::string &name, unsigned ttl); + + int parse(const char *buf, size_t len, const char *pos, size_t rrlen); + +public: + /** + * @brief Socket address. + */ + const sockaddr_in6 &addr_in6() const { return mSA.sin6; } +}; + +/** + * @class LLHostRecord + * @brief Base class for host-related RRs. + */ +class LLHostRecord : public LLDnsRecord +{ +protected: + LLHostRecord(LLResType type, const std::string &name, unsigned ttl); + + int parse(const char *buf, size_t len, const char *pos, size_t rrlen); + + std::string mHost; + +public: + /** + * @brief Host name. + */ + const std::string &host() const { return mHost; } +}; + +/** + * @class LLCnameRecord + * @brief CNAME RR. + */ +class LLCnameRecord : public LLHostRecord +{ +protected: + friend class LLQueryResponder; + + LLCnameRecord(const std::string &name, unsigned ttl); +}; + +/** + * @class LLPtrRecord + * @brief PTR RR. + */ +class LLPtrRecord : public LLHostRecord +{ +protected: + friend class LLQueryResponder; + + LLPtrRecord(const std::string &name, unsigned ttl); +}; + +/** + * @class LLSrvRecord + * @brief SRV RR. + */ +class LLSrvRecord : public LLHostRecord +{ +protected: + U16 mPriority; + U16 mWeight; + U16 mPort; + + int parse(const char *buf, size_t len, const char *pos, size_t rrlen); + +public: + LLSrvRecord(const std::string &name, unsigned ttl); + + /** + * @brief Service priority. + */ + U16 priority() const { return mPriority; } + + /** + * @brief Service weight. + */ + U16 weight() const { return mWeight; } + + /** + * @brief Port number of service. + */ + U16 port() const { return mPort; } + + /** + * @brief Functor for sorting SRV records by priority. + */ + struct ComparePriorityLowest + { + bool operator()(const LLSrvRecord& lhs, const LLSrvRecord& rhs) + { + return lhs.mPriority < rhs.mPriority; + } + }; +}; + +/** + * @class LLNsRecord + * @brief NS RR. + */ +class LLNsRecord : public LLHostRecord +{ +public: + LLNsRecord(const std::string &name, unsigned ttl); +}; + +class LLQueryResponder; + +/** + * @class LLAres + * @brief Asynchronous address resolver. + */ +class LLAres +{ +public: + /** + * @class HostResponder + * @brief Base class for responding to hostname lookups. + * @see LLAres::getHostByName + */ + class HostResponder : public LLRefCount + { + public: + virtual ~HostResponder(); + + virtual void hostResult(const hostent *ent); + virtual void hostError(int code); + }; + + /** + * @class NameInfoResponder + * @brief Base class for responding to address lookups. + * @see LLAres::getNameInfo + */ + class NameInfoResponder : public LLRefCount + { + public: + virtual ~NameInfoResponder(); + + virtual void nameInfoResult(const char *node, const char *service); + virtual void nameInfoError(int code); + }; + + /** + * @class QueryResponder + * @brief Base class for responding to custom searches. + * @see LLAres::search + */ + class QueryResponder : public LLRefCount + { + public: + virtual ~QueryResponder(); + + virtual void queryResult(const char *buf, size_t len); + virtual void queryError(int code); + }; + + class SrvResponder; + class UriRewriteResponder; + + LLAres(); + + ~LLAres(); + + /** + * Cancel all outstanding requests. The error methods of the + * corresponding responders will be called, with ARES_ETIMEOUT. + */ + void cancel(); + + /** + * Look up the address of a host. + * + * @param name name of host to look up + * @param resp responder to call with result + * @param family AF_INET for IPv4 addresses, AF_INET6 for IPv6 + */ + void getHostByName(const std::string &name, HostResponder *resp, + int family = AF_INET) { + getHostByName(name.c_str(), resp, family); + } + + /** + * Look up the address of a host. + * + * @param name name of host to look up + * @param resp responder to call with result + * @param family AF_INET for IPv4 addresses, AF_INET6 for IPv6 + */ + void getHostByName(const char *name, HostResponder *resp, + int family = PF_INET); + + /** + * Look up the name associated with a socket address. + * + * @param sa socket address to look up + * @param salen size of socket address + * @param flags flags to use + * @param resp responder to call with result + */ + void getNameInfo(const struct sockaddr &sa, socklen_t salen, int flags, + NameInfoResponder *resp); + + /** + * Look up SRV (service location) records for a service name. + * + * @param name service name (e.g. "_https._tcp.login.agni.lindenlab.com") + * @param resp responder to call with result + */ + void getSrvRecords(const std::string &name, SrvResponder *resp); + + /** + * Rewrite a URI, using SRV (service location) records for its + * protocol if available. If no SRV records are published, the + * existing URI is handed to the responder. + * + * @param uri URI to rewrite + * @param resp responder to call with result + */ + void rewriteURI(const std::string &uri, + UriRewriteResponder *resp); + + /** + * Start a custom search. + * + * @param query query to make + * @param type type of query to perform + * @param resp responder to call with result + */ + void search(const std::string &query, LLResType type, + QueryResponder *resp); + + /** + * Process any outstanding queries. This method takes an optional + * timeout parameter (specified in microseconds). If provided, it + * will block the calling thread for that length of time to await + * possible responses. A timeout of zero will return immediately + * if there are no responses or timeouts to process. + * + * @param timeoutUsecs number of microseconds to block before timing out + * @return whether any responses were processed + */ + bool process(U64 timeoutUsecs = 0); + + /** + * Process all outstanding queries, blocking the calling thread + * until all have either been responded to or timed out. + * + * @return whether any responses were processed + */ + bool processAll(); + + /** + * Expand a DNS-encoded compressed string into a normal string. + * + * @param encoded the encoded name (null-terminated) + * @param abuf the response buffer in which the string is embedded + * @param alen the length of the response buffer + * @param s the string into which to place the result + * @return ARES_SUCCESS on success, otherwise an error indicator + */ + static int expandName(const char *encoded, const char *abuf, size_t alen, + std::string &s) { + size_t ignore; + return expandName(encoded, abuf, alen, s, ignore); + } + + static int expandName(const char *encoded, const char *abuf, size_t alen, + std::string &s, size_t &enclen); + + /** + * Return a string describing an error code. + */ + static const char *strerror(int code); + +protected: + ares_channel chan_; + +}; + +/** + * An ordered collection of DNS resource records. + */ +typedef std::vector<LLPointer<LLDnsRecord> > dns_rrs_t; + +/** + * @class LLQueryResponder + * @brief Base class for friendly handling of DNS query responses. + * + * This class parses a DNS response and represents it in a friendly + * manner. + * + * @see LLDnsRecord + * @see LLARecord + * @see LLNsRecord + * @see LLCnameRecord + * @see LLPtrRecord + * @see LLAaaaRecord + * @see LLSrvRecord + */ +class LLQueryResponder : public LLAres::QueryResponder +{ +protected: + int mResult; + std::string mQuery; + LLResType mType; + + dns_rrs_t mAnswers; + dns_rrs_t mAuthorities; + dns_rrs_t mAdditional; + + /** + * Parse a single RR. + */ + int parseRR(const char *buf, size_t len, const char *&pos, + LLPointer<LLDnsRecord> &r); + /** + * Parse one section of a response. + */ + int parseSection(const char *buf, size_t len, + size_t count, const char *& pos, dns_rrs_t &rrs); + + void queryResult(const char *buf, size_t len); + virtual void querySuccess(); + +public: + LLQueryResponder(); + + /** + * Indicate whether the response could be parsed successfully. + */ + bool valid() const { return mResult == ARES_SUCCESS; } + + /** + * The more detailed result of parsing the response. + */ + int result() const { return mResult; } + + /** + * Return the query embedded in the response. + */ + const std::string &query() const { return mQuery; } + + /** + * Return the contents of the "answers" section of the response. + */ + const dns_rrs_t &answers() const { return mAnswers; } + + /** + * Return the contents of the "authorities" section of the + * response. + */ + const dns_rrs_t &authorities() const { return mAuthorities; } + + /** + * Return the contents of the "additional records" section of the + * response. + */ + const dns_rrs_t &additional() const { return mAdditional; } +}; + +/** + * @class LLAres::SrvResponder + * @brief Class for handling SRV query responses. + */ +class LLAres::SrvResponder : public LLQueryResponder +{ +public: + friend void LLAres::getSrvRecords(const std::string &name, + SrvResponder *resp); + void querySuccess(); + void queryError(int code); + + virtual void srvResult(const dns_rrs_t &ents); + virtual void srvError(int code); +}; + +/** + * @class LLAres::UriRewriteResponder + * @brief Class for handling URI rewrites based on SRV records. + */ +class LLAres::UriRewriteResponder : public LLQueryResponder +{ +protected: + LLURI mUri; + +public: + friend void LLAres::rewriteURI(const std::string &uri, + UriRewriteResponder *resp); + void querySuccess(); + void queryError(int code); + + virtual void rewriteResult(const std::vector<std::string> &uris); +}; + +/** + * Singleton responder. + */ +extern LLAres *gAres; + +/** + * Set up the singleton responder. It's safe to call this more than + * once from within a single thread, but this function is not + * thread safe. + */ +extern LLAres *ll_init_ares(); + +#endif // LL_LLARES_H |