aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llsrv.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/newview/llsrv.cpp')
-rw-r--r--linden/indra/newview/llsrv.cpp213
1 files changed, 213 insertions, 0 deletions
diff --git a/linden/indra/newview/llsrv.cpp b/linden/indra/newview/llsrv.cpp
new file mode 100644
index 0000000..4dec48d
--- /dev/null
+++ b/linden/indra/newview/llsrv.cpp
@@ -0,0 +1,213 @@
1/**
2 * @file llsrv.cpp
3 * @brief Wrapper for DNS SRV record lookups
4 *
5 * Copyright (c) 2007-2007, Linden Research, Inc.
6 *
7 * Second Life Viewer Source Code
8 * The source code in this file ("Source Code") is provided by Linden Lab
9 * to you under the terms of the GNU General Public License, version 2.0
10 * ("GPL"), unless you have obtained a separate licensing agreement
11 * ("Other License"), formally executed by you and Linden Lab. Terms of
12 * the GPL can be found in doc/GPL-license.txt in this distribution, or
13 * online at http://secondlife.com/developers/opensource/gplv2
14 *
15 * There are special exceptions to the terms and conditions of the GPL as
16 * it is applied to this Source Code. View the full text of the exception
17 * in the file doc/FLOSS-exception.txt in this software distribution, or
18 * online at http://secondlife.com/developers/opensource/flossexception
19 *
20 * By copying, modifying or distributing this software, you acknowledge
21 * that you have read and understood your obligations described above,
22 * and agree to abide by those obligations.
23 *
24 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
25 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
26 * COMPLETENESS OR PERFORMANCE.
27 */
28
29#include "llviewerprecompiledheaders.h"
30
31#include "llsrv.h"
32
33using namespace std;
34
35#if LL_WINDOWS
36
37#undef UNICODE
38#include <winsock2.h>
39#include <windns.h>
40
41vector<LLSRVRecord> LLSRV::query(const string& name)
42{
43 vector<LLSRVRecord> recs;
44 DNS_RECORD *rec;
45 DNS_STATUS status;
46
47 status = DnsQuery(name.c_str(), DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &rec, NULL);
48 if (!status)
49 {
50 for (DNS_RECORD *cur = rec; cur != NULL; cur = cur->pNext)
51 {
52 if (cur->wType != DNS_TYPE_SRV)
53 {
54 continue;
55 }
56 recs.push_back(LLSRVRecord(cur->Data.Srv.wPriority,
57 cur->Data.Srv.wWeight,
58 cur->Data.Srv.pNameTarget,
59 cur->Data.Srv.wPort));
60 }
61 DnsRecordListFree(rec, DnsFreeRecordListDeep);
62 }
63
64 return recs;
65}
66
67#else // !LL_WINDOWS
68
69#include <netinet/in.h>
70#include <arpa/nameser.h>
71#include <arpa/nameser_compat.h>
72#include <resolv.h>
73
74#include <netdb.h>
75
76vector<LLSRVRecord> LLSRV::query(const string& queryName)
77{
78 unsigned char response[16384];
79 vector<LLSRVRecord> recs;
80 char name[1024];
81 int len;
82
83 len = res_query(queryName.c_str(), ns_c_in, ns_t_srv, response,
84 sizeof(response));
85
86 if (len == -1)
87 {
88 llinfos << "Query failed for " << queryName << llendl;
89 return recs;
90 }
91 else if (len > (int) sizeof(response))
92 {
93 llinfos << "Response too big for " << queryName
94 << " (capacity " << sizeof(response)
95 << ", response " << len << ")" << llendl;
96 return recs;
97 }
98
99 // We "should" be using libresolv's ns_initparse and ns_parserr to
100 // parse the result of our query. However, libresolv isn't
101 // packaged correctly on Linux (as of BIND 9), so neither of these
102 // functions is available without statically linking against
103 // libresolv. Ugh! So we parse the response ourselves.
104
105 const unsigned char *pos = response + sizeof(HEADER);
106 const unsigned char *end = response + len;
107 const HEADER *hdr = (const HEADER *) response;
108
109 // Skip over the query embedded in the response.
110
111 for (int q = ntohs(hdr->qdcount); q > 0; --q)
112 {
113 len = dn_expand(response, end, pos, name, sizeof(name));
114
115 if (len == -1)
116 {
117 llinfos << "Could not expand queried name in RR response" << llendl;
118 return recs;
119 }
120
121 pos += len + NS_QFIXEDSZ;
122 }
123
124 for (int a = ntohs(hdr->ancount); a > 0; --a)
125 {
126 static const ns_rr *rr;
127
128 len = dn_expand(response, end, pos, name, sizeof(name) - 1);
129 if (len == -1)
130 {
131 llinfos << "Could not expand response name in RR response" << llendl;
132 return recs;
133 }
134
135 // Skip over the resource name and headers we don't care about.
136
137 pos += len + sizeof(rr->type) + sizeof(rr->rr_class) +
138 sizeof(rr->ttl) + sizeof(rr->rdlength);
139
140 U16 prio;
141 U16 weight;
142 U16 port;
143
144 NS_GET16(prio, pos);
145 NS_GET16(weight, pos);
146 NS_GET16(port, pos);
147
148 len = dn_expand(response, end, pos, name, sizeof(name) - 1);
149
150 if (len == -1)
151 {
152 llinfos << "Could not expand name in RR response" << llendl;
153 return recs;
154 }
155
156 recs.push_back(LLSRVRecord(prio, weight, name, port));
157 }
158
159 // There are likely to be more records in the response, but we
160 // don't care about those, at least for now.
161
162 return recs;
163}
164
165#endif // LL_WINDOWS
166
167vector<string> LLSRV::rewriteURI(const string& uriStr)
168{
169 LLURI uri(uriStr);
170 const string& scheme = uri.scheme();
171 llinfos << "Rewriting " << uriStr << llendl;
172 string serviceName("_" + scheme + "._tcp." + uri.hostName());
173 llinfos << "Querying for " << serviceName << llendl;
174 vector<LLSRVRecord> srvs(LLSRV::query(serviceName));
175 vector<string> rewritten;
176
177 if (srvs.empty())
178 {
179 llinfos << "No query results; using " << uriStr << llendl;
180 rewritten.push_back(uriStr);
181 }
182 else
183 {
184 vector<LLSRVRecord>::const_iterator iter;
185 size_t maxSrvs = 3;
186 size_t i;
187
188 llinfos << "Got " << srvs.size() << " results" << llendl;
189 if (srvs.size() > maxSrvs)
190 {
191 llinfos << "Clamping to " << maxSrvs << llendl;
192 }
193
194 for (iter = srvs.begin(), i = 0;
195 iter != srvs.end() && i < maxSrvs; ++iter, ++i)
196 {
197 LLURI newUri(scheme,
198 uri.userName(),
199 uri.password(),
200 iter->target(),
201 uri.defaultPort() ? iter->port() : uri.hostPort(),
202 uri.escapedPath(),
203 uri.escapedQuery());
204 string newUriStr(newUri.asString());
205
206 llinfos << "Rewrite[" << i << "] " << newUriStr << llendl;
207
208 rewritten.push_back(newUriStr);
209 }
210 }
211
212 return rewritten;
213}