diff options
Diffstat (limited to 'linden/indra/newview/llsrv.cpp')
-rw-r--r-- | linden/indra/newview/llsrv.cpp | 213 |
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 | |||
33 | using namespace std; | ||
34 | |||
35 | #if LL_WINDOWS | ||
36 | |||
37 | #undef UNICODE | ||
38 | #include <winsock2.h> | ||
39 | #include <windns.h> | ||
40 | |||
41 | vector<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 | |||
76 | vector<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 | |||
167 | vector<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 | } | ||