diff options
Diffstat (limited to 'indra/newview/llsrv.cpp')
-rw-r--r-- | indra/newview/llsrv.cpp | 348 |
1 files changed, 13 insertions, 335 deletions
diff --git a/indra/newview/llsrv.cpp b/indra/newview/llsrv.cpp index 7669eb994a..07f14f780e 100644 --- a/indra/newview/llsrv.cpp +++ b/indra/newview/llsrv.cpp @@ -9,347 +9,25 @@ #include "llviewerprecompiledheaders.h" #include "llsrv.h" +#include "llares.h" -using namespace std; - -#if LL_WINDOWS - -#undef UNICODE -#include <winsock2.h> -#include <windns.h> - -vector<LLSRVRecord> LLSRV::query(const string& name) +struct Responder : public LLAres::UriRewriteResponder { - vector<LLSRVRecord> recs; - DNS_RECORD *rec; - DNS_STATUS status; - - status = DnsQuery(name.c_str(), DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &rec, NULL); - if (!status) - { - for (DNS_RECORD *cur = rec; cur != NULL; cur = cur->pNext) + std::vector<std::string> mUris; + void rewriteResult(const std::vector<std::string> &uris) { + for (size_t i = 0; i < uris.size(); i++) { - if (cur->wType != DNS_TYPE_SRV) - { - continue; - } - recs.push_back(LLSRVRecord(cur->Data.Srv.wPriority, - cur->Data.Srv.wWeight, - cur->Data.Srv.pNameTarget, - cur->Data.Srv.wPort)); + llinfos << "[" << i << "] " << uris[i] << llendl; } - DnsRecordListFree(rec, DnsFreeRecordListDeep); + mUris = uris; } +}; - return recs; -} - -#else // !LL_WINDOWS - -#include <netinet/in.h> -#include <arpa/nameser.h> -#include <arpa/nameser_compat.h> -#include <resolv.h> - -#include <netdb.h> - -#ifdef HOMEGROWN_RESPONSE_PARSER - -// We ought to be using libresolv's ns_initparse and ns_parserr to -// parse the result of our query. However, libresolv isn't packaged -// correctly on Linux (as of BIND 9), so neither of these functions is -// available without statically linking against libresolv. Ugh! This -// fallback function is available if we need to parse the response -// ourselves without relying too much on libresolv. It is NOT THE -// DEFAULT. - -vector<LLSRVRecord> LLSRV::parseResponse(const unsigned char *response, - int resp_len) +std::vector<std::string> LLSRV::rewriteURI(const std::string& uri) { - vector<LLSRVRecord> recs; - - const unsigned char *pos = response + sizeof(HEADER); - const unsigned char *end = response + resp_len; - const HEADER *hdr = (const HEADER *) response; - char name[1024]; - - // Skip over the query embedded in the response. - - for (int q = ntohs(hdr->qdcount); q > 0; --q) - { - int len = dn_expand(response, end, pos, name, sizeof(name)); - - if (len == -1) - { - llinfos << "Could not expand queried name in RR response" - << llendl; - goto bail; - } - - pos += len + NS_QFIXEDSZ; - } - - for (int a = ntohs(hdr->ancount); a > 0; --a) - { - static const ns_rr *rr; - - int len = dn_expand(response, end, pos, name, sizeof(name) - 1); - if (len == -1) - { - llinfos << "Could not expand response name in RR response" - << llendl; - goto bail; - } - - // Skip over the resource name and headers we don't care about. - - pos += len + sizeof(rr->type) + sizeof(rr->rr_class) + - sizeof(rr->ttl) + sizeof(rr->rdlength); - - U16 prio; - U16 weight; - U16 port; - - NS_GET16(prio, pos); - NS_GET16(weight, pos); - NS_GET16(port, pos); - - len = dn_expand(response, end, pos, name, sizeof(name) - 1); - - if (len == -1) - { - llinfos << "Could not expand name in RR response" << llendl; - goto bail; - } - - recs.push_back(LLSRVRecord(prio, weight, name, port)); - } - - // There are likely to be more records in the response, but we - // don't care about those, at least for now. -bail: - return reorder(recs); -} - -#else // HOMEGROWN_RESPONSE_PARSER - -// This version of the response parser is the one to use if libresolv -// is available and behaving itself. - -vector<LLSRVRecord> LLSRV::parseResponse(const unsigned char *response, - int resp_len) -{ - vector<LLSRVRecord> recs; - ns_msg hdr; - - if (ns_initparse(response, resp_len, &hdr)) - { - llinfos << "Could not parse response" << llendl; - goto bail; - } - - for (int i = 0; i < ns_msg_count(hdr, ns_s_an); i++) - { - ns_rr rr; - - if (ns_parserr(&hdr, ns_s_an, i, &rr)) - { - llinfos << "Could not parse RR" << llendl; - goto bail; - } - - if (ns_rr_type(rr) != ns_t_srv) - { - continue; - } - - const unsigned char *pos = ns_rr_rdata(rr); - U16 prio, weight, port; - char name[1024]; - int ret; - - NS_GET16(prio, pos); - NS_GET16(weight, pos); - NS_GET16(port, pos); - - ret = dn_expand(ns_msg_base(hdr), ns_msg_end(hdr), pos, - name, sizeof(name)); - - if (ret == -1) - { - llinfos << "Could not decompress name" << llendl; - goto bail; - } - - recs.push_back(LLSRVRecord(prio, weight, name, port)); - } - -bail: - return reorder(recs); -} - -#endif // HOMEGROWN_RESPONSE_PARSER - -vector<LLSRVRecord> LLSRV::query(const string& queryName) -{ - unsigned char response[16384]; - vector<LLSRVRecord> recs; - int len; - - len = res_query(queryName.c_str(), ns_c_in, ns_t_srv, response, - sizeof(response)); - - if (len == -1) - { - llinfos << "Query failed for " << queryName << llendl; - goto bail; - } - else if (len > (int) sizeof(response)) - { - llinfos << "Response too big for " << queryName - << " (capacity " << sizeof(response) - << ", response " << len << ")" << llendl; - goto bail; - } - - recs = parseResponse(response, len); -bail: - return reorder(recs); -} - -#endif // LL_WINDOWS - -// Implement the algorithm specified in RFC 2782 for dealing with RRs -// of differing priorities and weights. -vector<LLSRVRecord> LLSRV::reorder(vector<LLSRVRecord>& recs) -{ - typedef list<const LLSRVRecord *> reclist_t; - typedef map<U16, reclist_t> bucket_t; - vector<LLSRVRecord> newRecs; - bucket_t buckets; - - // Don't rely on the DNS server to shuffle responses. - - random_shuffle(recs.begin(), recs.end()); - - for (vector<LLSRVRecord>::const_iterator iter = recs.begin(); - iter != recs.end(); ++iter) - { - buckets[iter->priority()].push_back(&*iter); - } - - // Priorities take precedence over weights. - - for (bucket_t::iterator iter = buckets.begin(); - iter != buckets.end(); ++iter) - { - reclist_t& myPrio = iter->second; - reclist_t r; - - // RRs with weight zero go to the front of the intermediate - // list, so they'll have little chance of being chosen. - // Larger weights have a higher likelihood of selection. - - for (reclist_t::iterator i = myPrio.begin(); i != myPrio.end(); ) - { - if ((*i)->weight() == 0) - { - r.push_back(*i); - i = myPrio.erase(i); - } else { - ++i; - } - } - - r.insert(r.end(), myPrio.begin(), myPrio.end()); - - while (!r.empty()) - { - U32 total = 0; - - for (reclist_t::const_iterator i = r.begin(); i != r.end(); ++i) - { - total += (*i)->weight(); - } - - U32 target = total > 1 ? (rand() % total) : 0; - U32 partial = 0; - - for (reclist_t::iterator i = r.begin(); i != r.end(); ) - { - partial += (*i)->weight(); - if (partial >= target) - { - newRecs.push_back(**i); - i = r.erase(i); - } else { - ++i; - } - } - } - } - - // Order RRs by lowest numeric priority. The stable sort - // preserves the weight choices we made above. - - stable_sort(newRecs.begin(), newRecs.end(), - LLSRVRecord::ComparePriorityLowest()); - - return newRecs; -} - -vector<string> LLSRV::rewriteURI(const string& uriStr) -{ - LLURI uri(uriStr); - const string& scheme = uri.scheme(); - llinfos << "Rewriting " << uriStr << llendl; - string serviceName("_" + scheme + "._tcp." + uri.hostName()); - llinfos << "Querying for " << serviceName << llendl; - vector<LLSRVRecord> srvs(LLSRV::query(serviceName)); - vector<string> rewritten; - - if (srvs.empty()) - { - llinfos << "No query results; using " << uriStr << llendl; - rewritten.push_back(uriStr); - } - else - { - vector<LLSRVRecord>::const_iterator iter; - size_t maxSrvs = 3; - size_t i; - - llinfos << "Got " << srvs.size() << " results" << llendl; - for (iter = srvs.begin(); iter != srvs.end(); ++iter) - { - lldebugs << "host " << iter->target() << ':' << iter->port() - << " prio " << iter->priority() - << " weight " << iter->weight() - << llendl; - } - - if (srvs.size() > maxSrvs) - { - llinfos << "Clamping to " << maxSrvs << llendl; - } - - for (iter = srvs.begin(), i = 0; - iter != srvs.end() && i < maxSrvs; ++iter, ++i) - { - LLURI newUri(scheme, - uri.userName(), - uri.password(), - iter->target(), - uri.defaultPort() ? iter->port() : uri.hostPort(), - uri.escapedPath(), - uri.escapedQuery()); - string newUriStr(newUri.asString()); - - llinfos << "Rewrite[" << i << "] " << newUriStr << llendl; - - rewritten.push_back(newUriStr); - } - } + LLPointer<Responder> resp = new Responder; - return rewritten; + gAres->rewriteURI(uri, resp); + gAres->processAll(); + return resp->mUris; } |