diff options
Diffstat (limited to 'linden/indra/newview/llsrv.cpp')
-rw-r--r-- | linden/indra/newview/llsrv.cpp | 232 |
1 files changed, 197 insertions, 35 deletions
diff --git a/linden/indra/newview/llsrv.cpp b/linden/indra/newview/llsrv.cpp index 4dec48d..5a623bc 100644 --- a/linden/indra/newview/llsrv.cpp +++ b/linden/indra/newview/llsrv.cpp | |||
@@ -73,49 +73,37 @@ vector<LLSRVRecord> LLSRV::query(const string& name) | |||
73 | 73 | ||
74 | #include <netdb.h> | 74 | #include <netdb.h> |
75 | 75 | ||
76 | vector<LLSRVRecord> LLSRV::query(const string& queryName) | 76 | #ifdef HOMEGROWN_RESPONSE_PARSER |
77 | |||
78 | // We ought to be using libresolv's ns_initparse and ns_parserr to | ||
79 | // parse the result of our query. However, libresolv isn't packaged | ||
80 | // correctly on Linux (as of BIND 9), so neither of these functions is | ||
81 | // available without statically linking against libresolv. Ugh! This | ||
82 | // fallback function is available if we need to parse the response | ||
83 | // ourselves without relying too much on libresolv. It is NOT THE | ||
84 | // DEFAULT. | ||
85 | |||
86 | vector<LLSRVRecord> LLSRV::parseResponse(const unsigned char *response, | ||
87 | int resp_len) | ||
77 | { | 88 | { |
78 | unsigned char response[16384]; | ||
79 | vector<LLSRVRecord> recs; | 89 | 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 | 90 | ||
105 | const unsigned char *pos = response + sizeof(HEADER); | 91 | const unsigned char *pos = response + sizeof(HEADER); |
106 | const unsigned char *end = response + len; | 92 | const unsigned char *end = response + resp_len; |
107 | const HEADER *hdr = (const HEADER *) response; | 93 | const HEADER *hdr = (const HEADER *) response; |
94 | char name[1024]; | ||
108 | 95 | ||
109 | // Skip over the query embedded in the response. | 96 | // Skip over the query embedded in the response. |
110 | 97 | ||
111 | for (int q = ntohs(hdr->qdcount); q > 0; --q) | 98 | for (int q = ntohs(hdr->qdcount); q > 0; --q) |
112 | { | 99 | { |
113 | len = dn_expand(response, end, pos, name, sizeof(name)); | 100 | int len = dn_expand(response, end, pos, name, sizeof(name)); |
114 | 101 | ||
115 | if (len == -1) | 102 | if (len == -1) |
116 | { | 103 | { |
117 | llinfos << "Could not expand queried name in RR response" << llendl; | 104 | llinfos << "Could not expand queried name in RR response" |
118 | return recs; | 105 | << llendl; |
106 | goto bail; | ||
119 | } | 107 | } |
120 | 108 | ||
121 | pos += len + NS_QFIXEDSZ; | 109 | pos += len + NS_QFIXEDSZ; |
@@ -125,11 +113,12 @@ vector<LLSRVRecord> LLSRV::query(const string& queryName) | |||
125 | { | 113 | { |
126 | static const ns_rr *rr; | 114 | static const ns_rr *rr; |
127 | 115 | ||
128 | len = dn_expand(response, end, pos, name, sizeof(name) - 1); | 116 | int len = dn_expand(response, end, pos, name, sizeof(name) - 1); |
129 | if (len == -1) | 117 | if (len == -1) |
130 | { | 118 | { |
131 | llinfos << "Could not expand response name in RR response" << llendl; | 119 | llinfos << "Could not expand response name in RR response" |
132 | return recs; | 120 | << llendl; |
121 | goto bail; | ||
133 | } | 122 | } |
134 | 123 | ||
135 | // Skip over the resource name and headers we don't care about. | 124 | // Skip over the resource name and headers we don't care about. |
@@ -150,7 +139,7 @@ vector<LLSRVRecord> LLSRV::query(const string& queryName) | |||
150 | if (len == -1) | 139 | if (len == -1) |
151 | { | 140 | { |
152 | llinfos << "Could not expand name in RR response" << llendl; | 141 | llinfos << "Could not expand name in RR response" << llendl; |
153 | return recs; | 142 | goto bail; |
154 | } | 143 | } |
155 | 144 | ||
156 | recs.push_back(LLSRVRecord(prio, weight, name, port)); | 145 | recs.push_back(LLSRVRecord(prio, weight, name, port)); |
@@ -158,12 +147,177 @@ vector<LLSRVRecord> LLSRV::query(const string& queryName) | |||
158 | 147 | ||
159 | // There are likely to be more records in the response, but we | 148 | // There are likely to be more records in the response, but we |
160 | // don't care about those, at least for now. | 149 | // don't care about those, at least for now. |
150 | bail: | ||
151 | return reorder(recs); | ||
152 | } | ||
161 | 153 | ||
162 | return recs; | 154 | #else // HOMEGROWN_RESPONSE_PARSER |
155 | |||
156 | // This version of the response parser is the one to use if libresolv | ||
157 | // is available and behaving itself. | ||
158 | |||
159 | vector<LLSRVRecord> LLSRV::parseResponse(const unsigned char *response, | ||
160 | int resp_len) | ||
161 | { | ||
162 | vector<LLSRVRecord> recs; | ||
163 | ns_msg hdr; | ||
164 | |||
165 | if (ns_initparse(response, resp_len, &hdr)) | ||
166 | { | ||
167 | llinfos << "Could not parse response" << llendl; | ||
168 | goto bail; | ||
169 | } | ||
170 | |||
171 | for (int i = 0; i < ns_msg_count(hdr, ns_s_an); i++) | ||
172 | { | ||
173 | ns_rr rr; | ||
174 | |||
175 | if (ns_parserr(&hdr, ns_s_an, i, &rr)) | ||
176 | { | ||
177 | llinfos << "Could not parse RR" << llendl; | ||
178 | goto bail; | ||
179 | } | ||
180 | |||
181 | if (ns_rr_type(rr) != ns_t_srv) | ||
182 | { | ||
183 | continue; | ||
184 | } | ||
185 | |||
186 | const unsigned char *pos = ns_rr_rdata(rr); | ||
187 | U16 prio, weight, port; | ||
188 | char name[1024]; | ||
189 | int ret; | ||
190 | |||
191 | NS_GET16(prio, pos); | ||
192 | NS_GET16(weight, pos); | ||
193 | NS_GET16(port, pos); | ||
194 | |||
195 | ret = dn_expand(ns_msg_base(hdr), ns_msg_end(hdr), pos, | ||
196 | name, sizeof(name)); | ||
197 | |||
198 | if (ret == -1) | ||
199 | { | ||
200 | llinfos << "Could not decompress name" << llendl; | ||
201 | goto bail; | ||
202 | } | ||
203 | |||
204 | recs.push_back(LLSRVRecord(prio, weight, name, port)); | ||
205 | } | ||
206 | |||
207 | bail: | ||
208 | return reorder(recs); | ||
209 | } | ||
210 | |||
211 | #endif // HOMEGROWN_RESPONSE_PARSER | ||
212 | |||
213 | vector<LLSRVRecord> LLSRV::query(const string& queryName) | ||
214 | { | ||
215 | unsigned char response[16384]; | ||
216 | vector<LLSRVRecord> recs; | ||
217 | int len; | ||
218 | |||
219 | len = res_query(queryName.c_str(), ns_c_in, ns_t_srv, response, | ||
220 | sizeof(response)); | ||
221 | |||
222 | if (len == -1) | ||
223 | { | ||
224 | llinfos << "Query failed for " << queryName << llendl; | ||
225 | goto bail; | ||
226 | } | ||
227 | else if (len > (int) sizeof(response)) | ||
228 | { | ||
229 | llinfos << "Response too big for " << queryName | ||
230 | << " (capacity " << sizeof(response) | ||
231 | << ", response " << len << ")" << llendl; | ||
232 | goto bail; | ||
233 | } | ||
234 | |||
235 | recs = parseResponse(response, len); | ||
236 | bail: | ||
237 | return reorder(recs); | ||
163 | } | 238 | } |
164 | 239 | ||
165 | #endif // LL_WINDOWS | 240 | #endif // LL_WINDOWS |
166 | 241 | ||
242 | // Implement the algorithm specified in RFC 2782 for dealing with RRs | ||
243 | // of differing priorities and weights. | ||
244 | vector<LLSRVRecord> LLSRV::reorder(vector<LLSRVRecord>& recs) | ||
245 | { | ||
246 | typedef list<const LLSRVRecord *> reclist_t; | ||
247 | typedef map<U16, reclist_t> bucket_t; | ||
248 | vector<LLSRVRecord> newRecs; | ||
249 | bucket_t buckets; | ||
250 | |||
251 | // Don't rely on the DNS server to shuffle responses. | ||
252 | |||
253 | random_shuffle(recs.begin(), recs.end()); | ||
254 | |||
255 | for (vector<LLSRVRecord>::const_iterator iter = recs.begin(); | ||
256 | iter != recs.end(); ++iter) | ||
257 | { | ||
258 | buckets[iter->priority()].push_back(&*iter); | ||
259 | } | ||
260 | |||
261 | // Priorities take precedence over weights. | ||
262 | |||
263 | for (bucket_t::iterator iter = buckets.begin(); | ||
264 | iter != buckets.end(); ++iter) | ||
265 | { | ||
266 | reclist_t& myPrio = iter->second; | ||
267 | reclist_t r; | ||
268 | |||
269 | // RRs with weight zero go to the front of the intermediate | ||
270 | // list, so they'll have little chance of being chosen. | ||
271 | // Larger weights have a higher likelihood of selection. | ||
272 | |||
273 | for (reclist_t::iterator i = myPrio.begin(); i != myPrio.end(); ) | ||
274 | { | ||
275 | if ((*i)->weight() == 0) | ||
276 | { | ||
277 | r.push_back(*i); | ||
278 | i = myPrio.erase(i); | ||
279 | } else { | ||
280 | ++i; | ||
281 | } | ||
282 | } | ||
283 | |||
284 | r.insert(r.end(), myPrio.begin(), myPrio.end()); | ||
285 | |||
286 | while (!r.empty()) | ||
287 | { | ||
288 | U32 total = 0; | ||
289 | |||
290 | for (reclist_t::const_iterator i = r.begin(); i != r.end(); ++i) | ||
291 | { | ||
292 | total += (*i)->weight(); | ||
293 | } | ||
294 | |||
295 | U32 target = total > 1 ? (rand() % total) : 0; | ||
296 | U32 partial = 0; | ||
297 | |||
298 | for (reclist_t::iterator i = r.begin(); i != r.end(); ) | ||
299 | { | ||
300 | partial += (*i)->weight(); | ||
301 | if (partial >= target) | ||
302 | { | ||
303 | newRecs.push_back(**i); | ||
304 | i = r.erase(i); | ||
305 | } else { | ||
306 | ++i; | ||
307 | } | ||
308 | } | ||
309 | } | ||
310 | } | ||
311 | |||
312 | // Order RRs by lowest numeric priority. The stable sort | ||
313 | // preserves the weight choices we made above. | ||
314 | |||
315 | stable_sort(newRecs.begin(), newRecs.end(), | ||
316 | LLSRVRecord::ComparePriorityLowest()); | ||
317 | |||
318 | return newRecs; | ||
319 | } | ||
320 | |||
167 | vector<string> LLSRV::rewriteURI(const string& uriStr) | 321 | vector<string> LLSRV::rewriteURI(const string& uriStr) |
168 | { | 322 | { |
169 | LLURI uri(uriStr); | 323 | LLURI uri(uriStr); |
@@ -186,6 +340,14 @@ vector<string> LLSRV::rewriteURI(const string& uriStr) | |||
186 | size_t i; | 340 | size_t i; |
187 | 341 | ||
188 | llinfos << "Got " << srvs.size() << " results" << llendl; | 342 | llinfos << "Got " << srvs.size() << " results" << llendl; |
343 | for (iter = srvs.begin(); iter != srvs.end(); ++iter) | ||
344 | { | ||
345 | lldebugs << "host " << iter->target() << ':' << iter->port() | ||
346 | << " prio " << iter->priority() | ||
347 | << " weight " << iter->weight() | ||
348 | << llendl; | ||
349 | } | ||
350 | |||
189 | if (srvs.size() > maxSrvs) | 351 | if (srvs.size() > maxSrvs) |
190 | { | 352 | { |
191 | llinfos << "Clamping to " << maxSrvs << llendl; | 353 | llinfos << "Clamping to " << maxSrvs << llendl; |