aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llmessage/llares.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-09-06 18:24:57 -0500
committerJacek Antonelli2008-09-06 18:25:07 -0500
commit798d367d54a6c6379ad355bd8345fa40e31e7fe9 (patch)
tree1921f1708cd0240648c97bc02df2c2ab5f2fc41e /linden/indra/llmessage/llares.cpp
parentSecond Life viewer sources 1.20.15 (diff)
downloadmeta-impy-798d367d54a6c6379ad355bd8345fa40e31e7fe9.zip
meta-impy-798d367d54a6c6379ad355bd8345fa40e31e7fe9.tar.gz
meta-impy-798d367d54a6c6379ad355bd8345fa40e31e7fe9.tar.bz2
meta-impy-798d367d54a6c6379ad355bd8345fa40e31e7fe9.tar.xz
Second Life viewer sources 1.21.0-RC
Diffstat (limited to 'linden/indra/llmessage/llares.cpp')
-rw-r--r--linden/indra/llmessage/llares.cpp804
1 files changed, 804 insertions, 0 deletions
diff --git a/linden/indra/llmessage/llares.cpp b/linden/indra/llmessage/llares.cpp
new file mode 100644
index 0000000..5a310b3
--- /dev/null
+++ b/linden/indra/llmessage/llares.cpp
@@ -0,0 +1,804 @@
1/**
2 * @file llares.cpp
3 * @author Bryan O'Sullivan
4 * @date 2007-08-15
5 * @brief Wrapper for asynchronous DNS lookups.
6 *
7 * $LicenseInfo:firstyear=2007&license=viewergpl$
8 *
9 * Copyright (c) 2007-2008, Linden Research, Inc.
10 *
11 * Second Life Viewer Source Code
12 * The source code in this file ("Source Code") is provided by Linden Lab
13 * to you under the terms of the GNU General Public License, version 2.0
14 * ("GPL"), unless you have obtained a separate licensing agreement
15 * ("Other License"), formally executed by you and Linden Lab. Terms of
16 * the GPL can be found in doc/GPL-license.txt in this distribution, or
17 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
18 *
19 * There are special exceptions to the terms and conditions of the GPL as
20 * it is applied to this Source Code. View the full text of the exception
21 * in the file doc/FLOSS-exception.txt in this software distribution, or
22 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
23 *
24 * By copying, modifying or distributing this software, you acknowledge
25 * that you have read and understood your obligations described above,
26 * and agree to abide by those obligations.
27 *
28 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
29 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
30 * COMPLETENESS OR PERFORMANCE.
31 * $/LicenseInfo$
32 */
33
34#include "linden_common.h"
35
36#include <ares_dns.h>
37#include <ares_version.h>
38
39#include "apr_portable.h"
40#include "apr_network_io.h"
41#include "apr_poll.h"
42
43#include "llapr.h"
44#include "llares.h"
45
46#if defined(LL_WINDOWS)
47# define ns_c_in 1
48# define NS_HFIXEDSZ 12 /* #/bytes of fixed data in header */
49# define NS_QFIXEDSZ 4 /* #/bytes of fixed data in query */
50# define NS_RRFIXEDSZ 10 /* #/bytes of fixed data in r record */
51#else
52# include <arpa/nameser.h>
53#endif
54
55LLAres::HostResponder::~HostResponder()
56{
57}
58
59void LLAres::HostResponder::hostResult(const hostent *ent)
60{
61 llinfos << "LLAres::HostResponder::hostResult not implemented" << llendl;
62}
63
64void LLAres::HostResponder::hostError(int code)
65{
66 llinfos << "LLAres::HostResponder::hostError " << code << ": "
67 << LLAres::strerror(code) << llendl;
68}
69
70LLAres::NameInfoResponder::~NameInfoResponder()
71{
72}
73
74void LLAres::NameInfoResponder::nameInfoResult(const char *node,
75 const char *service)
76{
77 llinfos << "LLAres::NameInfoResponder::nameInfoResult not implemented"
78 << llendl;
79}
80
81void LLAres::NameInfoResponder::nameInfoError(int code)
82{
83 llinfos << "LLAres::NameInfoResponder::nameInfoError " << code << ": "
84 << LLAres::strerror(code) << llendl;
85}
86
87LLAres::QueryResponder::~QueryResponder()
88{
89}
90
91void LLAres::QueryResponder::queryResult(const char *buf, size_t len)
92{
93 llinfos << "LLAres::QueryResponder::queryResult not implemented"
94 << llendl;
95}
96
97void LLAres::QueryResponder::queryError(int code)
98{
99 llinfos << "LLAres::QueryResponder::queryError " << code << ": "
100 << LLAres::strerror(code) << llendl;
101}
102
103LLAres::LLAres()
104{
105 ares_init(&chan_);
106}
107
108LLAres::~LLAres()
109{
110 ares_destroy(chan_);
111}
112
113void LLAres::cancel()
114{
115 ares_cancel(chan_);
116}
117
118static void host_callback_1_5(void *arg, int status, int timeouts,
119 struct hostent *ent)
120{
121 LLPointer<LLAres::HostResponder> *resp =
122 (LLPointer<LLAres::HostResponder> *) arg;
123
124 if (status == ARES_SUCCESS)
125 {
126 (*resp)->hostResult(ent);
127 } else {
128 (*resp)->hostError(status);
129 }
130
131 delete resp;
132}
133
134#if ARES_VERSION_MAJOR == 1 && ARES_VERSION_MINOR == 4
135static void host_callback(void *arg, int status, struct hostent *ent)
136{
137 host_callback_1_5(arg, status, 0, ent);
138}
139#else
140# define host_callback host_callback_1_5
141#endif
142
143void LLAres::getHostByName(const char *name, HostResponder *resp,
144 int family)
145{
146 ares_gethostbyname(chan_, name, family, host_callback,
147 new LLPointer<LLAres::HostResponder>(resp));
148}
149
150void LLAres::getSrvRecords(const std::string &name, SrvResponder *resp)
151{
152 search(name, RES_SRV, resp);
153}
154
155void LLAres::rewriteURI(const std::string &uri, UriRewriteResponder *resp)
156{
157 llinfos << "Rewriting " << uri << llendl;
158
159 resp->mUri = LLURI(uri);
160 search("_" + resp->mUri.scheme() + "._tcp." + resp->mUri.hostName(),
161 RES_SRV, resp);
162}
163
164LLQueryResponder::LLQueryResponder()
165 : LLAres::QueryResponder(),
166 mResult(ARES_ENODATA)
167{
168}
169
170int LLQueryResponder::parseRR(const char *buf, size_t len, const char *&pos,
171 LLPointer<LLDnsRecord> &r)
172{
173 std::string rrname;
174 size_t enclen;
175 int ret;
176
177 // RR name.
178
179 ret = LLAres::expandName(pos, buf, len, rrname, enclen);
180 if (ret != ARES_SUCCESS)
181 {
182 return ret;
183 }
184
185 pos += enclen;
186
187 if (pos + NS_RRFIXEDSZ > buf + len)
188 {
189 return ARES_EBADRESP;
190 }
191
192 int rrtype = DNS_RR_TYPE(pos);
193 int rrclass = DNS_RR_CLASS(pos);
194 int rrttl = DNS_RR_TTL(pos);
195 int rrlen = DNS_RR_LEN(pos);
196
197 if (rrclass != ns_c_in)
198 {
199 return ARES_EBADRESP;
200 }
201
202 pos += NS_RRFIXEDSZ;
203
204 if (pos + rrlen > buf + len)
205 {
206 return ARES_EBADRESP;
207 }
208
209 switch (rrtype)
210 {
211 case RES_A:
212 r = new LLARecord(rrname, rrttl);
213 break;
214 case RES_NS:
215 r = new LLNsRecord(rrname, rrttl);
216 break;
217 case RES_CNAME:
218 r = new LLCnameRecord(rrname, rrttl);
219 break;
220 case RES_PTR:
221 r = new LLPtrRecord(rrname, rrttl);
222 break;
223 case RES_AAAA:
224 r = new LLAaaaRecord(rrname, rrttl);
225 break;
226 case RES_SRV:
227 r = new LLSrvRecord(rrname, rrttl);
228 break;
229 default:
230 llinfos << "LLQueryResponder::parseRR got unknown RR type " << rrtype
231 << llendl;
232 return ARES_EBADRESP;
233 }
234
235 ret = r->parse(buf, len, pos, rrlen);
236
237 if (ret == ARES_SUCCESS)
238 {
239 pos += rrlen;
240 } else {
241 r = NULL;
242 }
243
244 return ret;
245}
246
247int LLQueryResponder::parseSection(const char *buf, size_t len,
248 size_t count, const char *&pos,
249 dns_rrs_t &rrs)
250{
251 int ret = ARES_SUCCESS;
252
253 for (size_t i = 0; i < count; i++)
254 {
255 LLPointer<LLDnsRecord> r;
256 ret = parseRR(buf, len, pos, r);
257 if (ret != ARES_SUCCESS)
258 {
259 break;
260 }
261 rrs.push_back(r);
262 }
263
264 return ret;
265}
266
267void LLQueryResponder::queryResult(const char *buf, size_t len)
268{
269 const char *pos = buf;
270 int qdcount = DNS_HEADER_QDCOUNT(pos);
271 int ancount = DNS_HEADER_ANCOUNT(pos);
272 int nscount = DNS_HEADER_NSCOUNT(pos);
273 int arcount = DNS_HEADER_ARCOUNT(pos);
274 int ret;
275
276 if (qdcount == 0 || ancount + nscount + arcount == 0)
277 {
278 ret = ARES_ENODATA;
279 goto bail;
280 }
281
282 pos += NS_HFIXEDSZ;
283
284 for (int i = 0; i < qdcount; i++)
285 {
286 std::string ignore;
287 size_t enclen;
288
289 ret = LLAres::expandName(pos, buf, len, i == 0 ? mQuery : ignore,
290 enclen);
291 if (ret != ARES_SUCCESS)
292 {
293 goto bail;
294 }
295
296 pos += enclen;
297
298 if (i == 0)
299 {
300 int t = DNS_QUESTION_TYPE(pos);
301 switch (t)
302 {
303 case RES_A:
304 case RES_NS:
305 case RES_CNAME:
306 case RES_PTR:
307 case RES_AAAA:
308 case RES_SRV:
309 mType = (LLResType) t;
310 break;
311 default:
312 llinfos << "Cannot grok query type " << t << llendl;
313 ret = ARES_EBADQUERY;
314 goto bail;
315 }
316 }
317
318 pos += NS_QFIXEDSZ;
319 if (pos > buf + len)
320 {
321 ret = ARES_EBADRESP;
322 goto bail;
323 }
324 }
325
326 ret = parseSection(buf, len, ancount, pos, mAnswers);
327 if (ret != ARES_SUCCESS)
328 {
329 goto bail;
330 }
331
332 ret = parseSection(buf, len, nscount, pos, mAuthorities);
333 if (ret != ARES_SUCCESS)
334 {
335 goto bail;
336 }
337
338 ret = parseSection(buf, len, arcount, pos, mAdditional);
339
340bail:
341 mResult = ret;
342 if (mResult == ARES_SUCCESS)
343 {
344 querySuccess();
345 } else {
346 queryError(mResult);
347 }
348}
349
350void LLQueryResponder::querySuccess()
351{
352 llinfos << "LLQueryResponder::queryResult not implemented" << llendl;
353}
354
355void LLAres::SrvResponder::querySuccess()
356{
357 if (mType == RES_SRV)
358 {
359 srvResult(mAnswers);
360 } else {
361 srvError(ARES_EBADRESP);
362 }
363}
364
365void LLAres::SrvResponder::queryError(int code)
366{
367 srvError(code);
368}
369
370void LLAres::SrvResponder::srvResult(const dns_rrs_t &ents)
371{
372 llinfos << "LLAres::SrvResponder::srvResult not implemented" << llendl;
373
374 for (size_t i = 0; i < ents.size(); i++)
375 {
376 const LLSrvRecord *s = (const LLSrvRecord *) ents[i].get();
377
378 llinfos << "[" << i << "] " << s->host() << ":" << s->port()
379 << " priority " << s->priority()
380 << " weight " << s->weight()
381 << llendl;
382 }
383}
384
385void LLAres::SrvResponder::srvError(int code)
386{
387 llinfos << "LLAres::SrvResponder::srvError " << code << ": "
388 << LLAres::strerror(code) << llendl;
389}
390
391static void nameinfo_callback_1_5(void *arg, int status, int timeouts,
392 char *node, char *service)
393{
394 LLPointer<LLAres::NameInfoResponder> *resp =
395 (LLPointer<LLAres::NameInfoResponder> *) arg;
396
397 if (status == ARES_SUCCESS)
398 {
399 (*resp)->nameInfoResult(node, service);
400 } else {
401 (*resp)->nameInfoError(status);
402 }
403
404 delete resp;
405}
406
407#if ARES_VERSION_MAJOR == 1 && ARES_VERSION_MINOR == 4
408static void nameinfo_callback(void *arg, int status, char *node, char *service)
409{
410 nameinfo_callback_1_5(arg, status, 0, node, service);
411}
412#else
413# define nameinfo_callback nameinfo_callback_1_5
414#endif
415
416void LLAres::getNameInfo(const struct sockaddr &sa, socklen_t salen, int flags,
417 NameInfoResponder *resp)
418{
419 ares_getnameinfo(chan_, &sa, salen, flags, nameinfo_callback,
420 new LLPointer<NameInfoResponder>(resp));
421}
422
423static void search_callback_1_5(void *arg, int status, int timeouts,
424 unsigned char *abuf, int alen)
425{
426 LLPointer<LLAres::QueryResponder> *resp =
427 (LLPointer<LLAres::QueryResponder> *) arg;
428
429 if (status == ARES_SUCCESS)
430 {
431 (*resp)->queryResult((const char *) abuf, alen);
432 } else {
433 (*resp)->queryError(status);
434 }
435
436 delete resp;
437}
438
439#if ARES_VERSION_MAJOR == 1 && ARES_VERSION_MINOR == 4
440static void search_callback(void *arg, int status, unsigned char *abuf,
441 int alen)
442{
443 search_callback_1_5(arg, status, 0, abuf, alen);
444}
445#else
446# define search_callback search_callback_1_5
447#endif
448
449void LLAres::search(const std::string &query, LLResType type,
450 QueryResponder *resp)
451{
452 ares_search(chan_, query.c_str(), ns_c_in, type, search_callback,
453 new LLPointer<QueryResponder>(resp));
454}
455
456bool LLAres::process(U64 timeout)
457{
458 if (!gAPRPoolp)
459 {
460 ll_init_apr();
461 }
462
463 int socks[ARES_GETSOCK_MAXNUM];
464 apr_pollfd_t aprFds[ARES_GETSOCK_MAXNUM];
465 apr_int32_t nsds = 0;
466 apr_status_t status;
467 apr_pool_t *pool;
468 int nactive = 0;
469 int bitmask;
470
471 bitmask = ares_getsock(chan_, socks, ARES_GETSOCK_MAXNUM);
472
473 if (bitmask == 0)
474 {
475 goto bail;
476 }
477
478 status = apr_pool_create(&pool, gAPRPoolp);
479 ll_apr_assert_status(status);
480
481 for (int i = 0; i < ARES_GETSOCK_MAXNUM; i++)
482 {
483 if (ARES_GETSOCK_READABLE(bitmask, i))
484 {
485 aprFds[nactive].reqevents = APR_POLLIN | APR_POLLERR;
486 }
487 else if (ARES_GETSOCK_WRITABLE(bitmask, i))
488 {
489 aprFds[nactive].reqevents = APR_POLLOUT | APR_POLLERR;
490 } else {
491 continue;
492 }
493
494 apr_socket_t *aprSock = NULL;
495
496 status = apr_os_sock_put(&aprSock, (apr_os_sock_t *) &socks[i], pool);
497 if (status != APR_SUCCESS)
498 {
499 ll_apr_warn_status(status);
500 goto bail_pool;
501 }
502
503 aprFds[nactive].desc.s = aprSock;
504 aprFds[nactive].desc_type = APR_POLL_SOCKET;
505 aprFds[nactive].p = pool;
506 aprFds[nactive].rtnevents = 0;
507 aprFds[nactive].client_data = &socks[i];
508
509 nactive++;
510 }
511
512 if (nactive > 0)
513 {
514 status = apr_poll(aprFds, nactive, &nsds, timeout);
515
516 if (status != APR_SUCCESS && status != APR_TIMEUP)
517 {
518 ll_apr_warn_status(status);
519 }
520
521 for (int i = 0; i < nactive; i++)
522 {
523 int evts = aprFds[i].rtnevents;
524 int ifd = (evts & (APR_POLLIN | APR_POLLERR))
525 ? *((int *) aprFds[i].client_data) : ARES_SOCKET_BAD;
526 int ofd = (evts & (APR_POLLOUT | APR_POLLERR))
527 ? *((int *) aprFds[i].client_data) : ARES_SOCKET_BAD;
528
529 ares_process_fd(chan_, ifd, ofd);
530 }
531 }
532
533bail_pool:
534 apr_pool_destroy(pool);
535
536bail:
537 return nsds > 0;
538}
539
540bool LLAres::processAll()
541{
542 bool anyProcessed = false, ret;
543
544 do {
545 timeval tv;
546
547 ret = ares_timeout(chan_, NULL, &tv) != NULL;
548
549 if (ret)
550 {
551 ret = process(tv.tv_sec * 1000000LL + tv.tv_usec);
552 anyProcessed |= ret;
553 }
554 } while (ret);
555
556 return anyProcessed;
557}
558
559int LLAres::expandName(const char *encoded, const char *abuf, size_t alen,
560 std::string &s, size_t &enclen)
561{
562 char *t;
563 int ret;
564 long e;
565
566 ret = ares_expand_name((const unsigned char *) encoded,
567 (const unsigned char *) abuf, alen, &t, &e);
568 if (ret == ARES_SUCCESS)
569 {
570 s.assign(t);
571 enclen = e;
572 ares_free_string(t);
573 }
574 return ret;
575}
576
577const char *LLAres::strerror(int code)
578{
579 return ares_strerror(code);
580}
581
582LLAres *gAres;
583
584LLAres *ll_init_ares()
585{
586 if (gAres == NULL)
587 {
588 gAres = new LLAres();
589 }
590 return gAres;
591}
592
593LLDnsRecord::LLDnsRecord(LLResType type, const std::string &name,
594 unsigned ttl)
595 : LLRefCount(),
596 mType(type),
597 mName(name),
598 mTTL(ttl)
599{
600}
601
602LLHostRecord::LLHostRecord(LLResType type, const std::string &name,
603 unsigned ttl)
604 : LLDnsRecord(type, name, ttl)
605{
606}
607
608int LLHostRecord::parse(const char *buf, size_t len, const char *pos,
609 size_t rrlen)
610{
611 int ret;
612
613 ret = LLAres::expandName(pos, buf, len, mHost);
614 if (ret != ARES_SUCCESS)
615 {
616 goto bail;
617 }
618
619 ret = ARES_SUCCESS;
620
621bail:
622 return ret;
623}
624
625LLCnameRecord::LLCnameRecord(const std::string &name, unsigned ttl)
626 : LLHostRecord(RES_CNAME, name, ttl)
627{
628}
629
630LLPtrRecord::LLPtrRecord(const std::string &name, unsigned ttl)
631 : LLHostRecord(RES_PTR, name, ttl)
632{
633}
634
635LLAddrRecord::LLAddrRecord(LLResType type, const std::string &name,
636 unsigned ttl)
637 : LLDnsRecord(type, name, ttl)
638{
639}
640
641LLARecord::LLARecord(const std::string &name, unsigned ttl)
642 : LLAddrRecord(RES_A, name, ttl)
643{
644}
645
646int LLARecord::parse(const char *buf, size_t len, const char *pos,
647 size_t rrlen)
648{
649 int ret;
650
651 if (rrlen != sizeof(mSA.sin.sin_addr.s_addr))
652 {
653 ret = ARES_EBADRESP;
654 goto bail;
655 }
656
657 memset(&mSA, 0, sizeof(mSA));
658 memcpy(&mSA.sin.sin_addr.s_addr, pos, rrlen);
659 mSA.sin.sin_family = AF_INET6;
660 mSize = sizeof(mSA.sin);
661
662 ret = ARES_SUCCESS;
663
664bail:
665 return ret;
666}
667
668LLAaaaRecord::LLAaaaRecord(const std::string &name, unsigned ttl)
669 : LLAddrRecord(RES_AAAA, name, ttl)
670{
671}
672
673int LLAaaaRecord::parse(const char *buf, size_t len, const char *pos,
674 size_t rrlen)
675{
676 int ret;
677
678 if (rrlen != sizeof(mSA.sin6.sin6_addr))
679 {
680 ret = ARES_EBADRESP;
681 goto bail;
682 }
683
684 memset(&mSA, 0, sizeof(mSA));
685 memcpy(&mSA.sin6.sin6_addr.s6_addr, pos, rrlen);
686 mSA.sin6.sin6_family = AF_INET6;
687 mSize = sizeof(mSA.sin6);
688
689 ret = ARES_SUCCESS;
690
691bail:
692 return ret;
693}
694
695LLSrvRecord::LLSrvRecord(const std::string &name, unsigned ttl)
696 : LLHostRecord(RES_SRV, name, ttl)
697{
698}
699
700int LLSrvRecord::parse(const char *buf, size_t len, const char *pos,
701 size_t rrlen)
702{
703 int ret;
704
705 if (rrlen < 6)
706 {
707 ret = ARES_EBADRESP;
708 goto bail;
709 }
710
711 memcpy(&mPriority, pos, 2);
712 memcpy(&mWeight, pos + 2, 2);
713 memcpy(&mPort, pos + 4, 2);
714
715 mPriority = ntohs(mPriority);
716 mWeight = ntohs(mWeight);
717 mPort = ntohs(mPort);
718
719 ret = LLHostRecord::parse(buf, len, pos + 6, rrlen - 6);
720
721bail:
722 return ret;
723}
724
725LLNsRecord::LLNsRecord(const std::string &name, unsigned ttl)
726 : LLHostRecord(RES_NS, name, ttl)
727{
728}
729
730void LLAres::UriRewriteResponder::queryError(int code)
731{
732 std::vector<std::string> uris;
733 uris.push_back(mUri.asString());
734 rewriteResult(uris);
735}
736
737void LLAres::UriRewriteResponder::querySuccess()
738{
739 std::vector<std::string> uris;
740
741 if (mType != RES_SRV)
742 {
743 goto bail;
744 }
745
746 for (size_t i = 0; i < mAnswers.size(); i++)
747 {
748 const LLSrvRecord *r = (const LLSrvRecord *) mAnswers[i].get();
749
750 if (r->type() == RES_SRV)
751 {
752 // Check the domain in the response to ensure that it's
753 // the same as the domain in the request, so that bad guys
754 // can't forge responses that point to their own login
755 // servers with their own certificates.
756
757 // Hard-coding the domain to check here is a bit of a
758 // hack. Hoist it to an outer caller if anyone ever needs
759 // this functionality on other domains.
760
761 static const std::string domain(".lindenlab.com");
762 const std::string &host = r->host();
763
764 std::string::size_type s = host.find(domain) + domain.length();
765
766 if (s != host.length() && s != host.length() - 1)
767 {
768 continue;
769 }
770
771 LLURI uri(mUri.scheme(),
772 mUri.userName(),
773 mUri.password(),
774 r->host(),
775 mUri.defaultPort() ? r->port() : mUri.hostPort(),
776 mUri.escapedPath(),
777 mUri.escapedQuery());
778 uris.push_back(uri.asString());
779 }
780 }
781
782 if (!uris.empty())
783 {
784 goto done;
785 }
786
787bail:
788 uris.push_back(mUri.asString());
789
790done:
791 rewriteResult(uris);
792}
793
794void LLAres::UriRewriteResponder::rewriteResult(
795 const std::vector<std::string> &uris)
796{
797 llinfos << "LLAres::UriRewriteResponder::rewriteResult not implemented"
798 << llendl;
799
800 for (size_t i = 0; i < uris.size(); i++)
801 {
802 llinfos << "[" << i << "] " << uris[i] << llendl;
803 }
804}