00001
00029 #include "llviewerprecompiledheaders.h"
00030
00031 #include "llsrv.h"
00032
00033 using namespace std;
00034
00035 #if LL_WINDOWS
00036
00037 #undef UNICODE
00038 #include <winsock2.h>
00039 #include <windns.h>
00040
00041 vector<LLSRVRecord> LLSRV::query(const string& name)
00042 {
00043 vector<LLSRVRecord> recs;
00044 DNS_RECORD *rec;
00045 DNS_STATUS status;
00046
00047 status = DnsQuery(name.c_str(), DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &rec, NULL);
00048 if (!status)
00049 {
00050 for (DNS_RECORD *cur = rec; cur != NULL; cur = cur->pNext)
00051 {
00052 if (cur->wType != DNS_TYPE_SRV)
00053 {
00054 continue;
00055 }
00056 recs.push_back(LLSRVRecord(cur->Data.Srv.wPriority,
00057 cur->Data.Srv.wWeight,
00058 cur->Data.Srv.pNameTarget,
00059 cur->Data.Srv.wPort));
00060 }
00061 DnsRecordListFree(rec, DnsFreeRecordListDeep);
00062 }
00063
00064 return recs;
00065 }
00066
00067 #else // !LL_WINDOWS
00068
00069 #include <netinet/in.h>
00070 #include <arpa/nameser.h>
00071 #include <arpa/nameser_compat.h>
00072 #include <resolv.h>
00073
00074 #include <netdb.h>
00075
00076 #ifdef HOMEGROWN_RESPONSE_PARSER
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086 vector<LLSRVRecord> LLSRV::parseResponse(const unsigned char *response,
00087 int resp_len)
00088 {
00089 vector<LLSRVRecord> recs;
00090
00091 const unsigned char *pos = response + sizeof(HEADER);
00092 const unsigned char *end = response + resp_len;
00093 const HEADER *hdr = (const HEADER *) response;
00094 char name[1024];
00095
00096
00097
00098 for (int q = ntohs(hdr->qdcount); q > 0; --q)
00099 {
00100 int len = dn_expand(response, end, pos, name, sizeof(name));
00101
00102 if (len == -1)
00103 {
00104 llinfos << "Could not expand queried name in RR response"
00105 << llendl;
00106 goto bail;
00107 }
00108
00109 pos += len + NS_QFIXEDSZ;
00110 }
00111
00112 for (int a = ntohs(hdr->ancount); a > 0; --a)
00113 {
00114 static const ns_rr *rr;
00115
00116 int len = dn_expand(response, end, pos, name, sizeof(name) - 1);
00117 if (len == -1)
00118 {
00119 llinfos << "Could not expand response name in RR response"
00120 << llendl;
00121 goto bail;
00122 }
00123
00124
00125
00126 pos += len + sizeof(rr->type) + sizeof(rr->rr_class) +
00127 sizeof(rr->ttl) + sizeof(rr->rdlength);
00128
00129 U16 prio;
00130 U16 weight;
00131 U16 port;
00132
00133 NS_GET16(prio, pos);
00134 NS_GET16(weight, pos);
00135 NS_GET16(port, pos);
00136
00137 len = dn_expand(response, end, pos, name, sizeof(name) - 1);
00138
00139 if (len == -1)
00140 {
00141 llinfos << "Could not expand name in RR response" << llendl;
00142 goto bail;
00143 }
00144
00145 recs.push_back(LLSRVRecord(prio, weight, name, port));
00146 }
00147
00148
00149
00150 bail:
00151 return reorder(recs);
00152 }
00153
00154 #else // HOMEGROWN_RESPONSE_PARSER
00155
00156
00157
00158
00159 vector<LLSRVRecord> LLSRV::parseResponse(const unsigned char *response,
00160 int resp_len)
00161 {
00162 vector<LLSRVRecord> recs;
00163 ns_msg hdr;
00164
00165 if (ns_initparse(response, resp_len, &hdr))
00166 {
00167 llinfos << "Could not parse response" << llendl;
00168 goto bail;
00169 }
00170
00171 for (int i = 0; i < ns_msg_count(hdr, ns_s_an); i++)
00172 {
00173 ns_rr rr;
00174
00175 if (ns_parserr(&hdr, ns_s_an, i, &rr))
00176 {
00177 llinfos << "Could not parse RR" << llendl;
00178 goto bail;
00179 }
00180
00181 if (ns_rr_type(rr) != ns_t_srv)
00182 {
00183 continue;
00184 }
00185
00186 const unsigned char *pos = ns_rr_rdata(rr);
00187 U16 prio, weight, port;
00188 char name[1024];
00189 int ret;
00190
00191 NS_GET16(prio, pos);
00192 NS_GET16(weight, pos);
00193 NS_GET16(port, pos);
00194
00195 ret = dn_expand(ns_msg_base(hdr), ns_msg_end(hdr), pos,
00196 name, sizeof(name));
00197
00198 if (ret == -1)
00199 {
00200 llinfos << "Could not decompress name" << llendl;
00201 goto bail;
00202 }
00203
00204 recs.push_back(LLSRVRecord(prio, weight, name, port));
00205 }
00206
00207 bail:
00208 return reorder(recs);
00209 }
00210
00211 #endif // HOMEGROWN_RESPONSE_PARSER
00212
00213 vector<LLSRVRecord> LLSRV::query(const string& queryName)
00214 {
00215 unsigned char response[16384];
00216 vector<LLSRVRecord> recs;
00217 int len;
00218
00219 len = res_query(queryName.c_str(), ns_c_in, ns_t_srv, response,
00220 sizeof(response));
00221
00222 if (len == -1)
00223 {
00224 llinfos << "Query failed for " << queryName << llendl;
00225 goto bail;
00226 }
00227 else if (len > (int) sizeof(response))
00228 {
00229 llinfos << "Response too big for " << queryName
00230 << " (capacity " << sizeof(response)
00231 << ", response " << len << ")" << llendl;
00232 goto bail;
00233 }
00234
00235 recs = parseResponse(response, len);
00236 bail:
00237 return reorder(recs);
00238 }
00239
00240 #endif // LL_WINDOWS
00241
00242
00243
00244 vector<LLSRVRecord> LLSRV::reorder(vector<LLSRVRecord>& recs)
00245 {
00246 typedef list<const LLSRVRecord *> reclist_t;
00247 typedef map<U16, reclist_t> bucket_t;
00248 vector<LLSRVRecord> newRecs;
00249 bucket_t buckets;
00250
00251
00252
00253 random_shuffle(recs.begin(), recs.end());
00254
00255 for (vector<LLSRVRecord>::const_iterator iter = recs.begin();
00256 iter != recs.end(); ++iter)
00257 {
00258 buckets[iter->priority()].push_back(&*iter);
00259 }
00260
00261
00262
00263 for (bucket_t::iterator iter = buckets.begin();
00264 iter != buckets.end(); ++iter)
00265 {
00266 reclist_t& myPrio = iter->second;
00267 reclist_t r;
00268
00269
00270
00271
00272
00273 for (reclist_t::iterator i = myPrio.begin(); i != myPrio.end(); )
00274 {
00275 if ((*i)->weight() == 0)
00276 {
00277 r.push_back(*i);
00278 i = myPrio.erase(i);
00279 } else {
00280 ++i;
00281 }
00282 }
00283
00284 r.insert(r.end(), myPrio.begin(), myPrio.end());
00285
00286 while (!r.empty())
00287 {
00288 U32 total = 0;
00289
00290 for (reclist_t::const_iterator i = r.begin(); i != r.end(); ++i)
00291 {
00292 total += (*i)->weight();
00293 }
00294
00295 U32 target = total > 1 ? (rand() % total) : 0;
00296 U32 partial = 0;
00297
00298 for (reclist_t::iterator i = r.begin(); i != r.end(); )
00299 {
00300 partial += (*i)->weight();
00301 if (partial >= target)
00302 {
00303 newRecs.push_back(**i);
00304 i = r.erase(i);
00305 } else {
00306 ++i;
00307 }
00308 }
00309 }
00310 }
00311
00312
00313
00314
00315 stable_sort(newRecs.begin(), newRecs.end(),
00316 LLSRVRecord::ComparePriorityLowest());
00317
00318 return newRecs;
00319 }
00320
00321 vector<string> LLSRV::rewriteURI(const string& uriStr)
00322 {
00323 LLURI uri(uriStr);
00324 const string& scheme = uri.scheme();
00325 llinfos << "Rewriting " << uriStr << llendl;
00326 string serviceName("_" + scheme + "._tcp." + uri.hostName());
00327 llinfos << "Querying for " << serviceName << llendl;
00328 vector<LLSRVRecord> srvs(LLSRV::query(serviceName));
00329 vector<string> rewritten;
00330
00331 if (srvs.empty())
00332 {
00333 llinfos << "No query results; using " << uriStr << llendl;
00334 rewritten.push_back(uriStr);
00335 }
00336 else
00337 {
00338 vector<LLSRVRecord>::const_iterator iter;
00339 size_t maxSrvs = 3;
00340 size_t i;
00341
00342 llinfos << "Got " << srvs.size() << " results" << llendl;
00343 for (iter = srvs.begin(); iter != srvs.end(); ++iter)
00344 {
00345 lldebugs << "host " << iter->target() << ':' << iter->port()
00346 << " prio " << iter->priority()
00347 << " weight " << iter->weight()
00348 << llendl;
00349 }
00350
00351 if (srvs.size() > maxSrvs)
00352 {
00353 llinfos << "Clamping to " << maxSrvs << llendl;
00354 }
00355
00356 for (iter = srvs.begin(), i = 0;
00357 iter != srvs.end() && i < maxSrvs; ++iter, ++i)
00358 {
00359 LLURI newUri(scheme,
00360 uri.userName(),
00361 uri.password(),
00362 iter->target(),
00363 uri.defaultPort() ? iter->port() : uri.hostPort(),
00364 uri.escapedPath(),
00365 uri.escapedQuery());
00366 string newUriStr(newUri.asString());
00367
00368 llinfos << "Rewrite[" << i << "] " << newUriStr << llendl;
00369
00370 rewritten.push_back(newUriStr);
00371 }
00372 }
00373
00374 return rewritten;
00375 }