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.cpp232
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
76vector<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
86vector<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.
150bail:
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
159vector<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
207bail:
208 return reorder(recs);
209}
210
211#endif // HOMEGROWN_RESPONSE_PARSER
212
213vector<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);
236bail:
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.
244vector<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
167vector<string> LLSRV::rewriteURI(const string& uriStr) 321vector<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;