MAINT-5629: Remove llares and llareslistener. Login now does not attempt to do a lookup on the server names and rewrite the URL.
MAINT-5614: Bad password status correctly detected.master
parent
cf835a80cd
commit
1eed334e7f
|
|
@ -28,8 +28,6 @@ include_directories(
|
|||
)
|
||||
|
||||
set(llmessage_SOURCE_FILES
|
||||
llares.cpp
|
||||
llareslistener.cpp
|
||||
llassetstorage.cpp
|
||||
llavatarname.cpp
|
||||
llavatarnamecache.cpp
|
||||
|
|
@ -109,8 +107,6 @@ set(llmessage_SOURCE_FILES
|
|||
set(llmessage_HEADER_FILES
|
||||
CMakeLists.txt
|
||||
|
||||
llares.h
|
||||
llareslistener.h
|
||||
llassetstorage.h
|
||||
llavatarname.h
|
||||
llavatarnamecache.h
|
||||
|
|
|
|||
|
|
@ -1,839 +0,0 @@
|
|||
/**
|
||||
* @file llares.cpp
|
||||
* @author Bryan O'Sullivan
|
||||
* @date 2007-08-15
|
||||
* @brief Wrapper for asynchronous DNS lookups.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llares.h"
|
||||
|
||||
#include <ares_dns.h>
|
||||
#include <ares_version.h>
|
||||
|
||||
#include "apr_portable.h"
|
||||
#include "apr_network_io.h"
|
||||
#include "apr_poll.h"
|
||||
|
||||
#include "llapr.h"
|
||||
#include "llareslistener.h"
|
||||
|
||||
#if defined(LL_WINDOWS)
|
||||
#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
|
||||
# define ns_c_in 1
|
||||
# define NS_HFIXEDSZ 12 /* #/bytes of fixed data in header */
|
||||
# define NS_QFIXEDSZ 4 /* #/bytes of fixed data in query */
|
||||
# define NS_RRFIXEDSZ 10 /* #/bytes of fixed data in r record */
|
||||
#else
|
||||
# include <arpa/nameser.h>
|
||||
#endif
|
||||
|
||||
LLAres::HostResponder::~HostResponder()
|
||||
{
|
||||
}
|
||||
|
||||
void LLAres::HostResponder::hostResult(const hostent *ent)
|
||||
{
|
||||
LL_INFOS() << "LLAres::HostResponder::hostResult not implemented" << LL_ENDL;
|
||||
}
|
||||
|
||||
void LLAres::HostResponder::hostError(int code)
|
||||
{
|
||||
LL_INFOS() << "LLAres::HostResponder::hostError " << code << ": "
|
||||
<< LLAres::strerror(code) << LL_ENDL;
|
||||
}
|
||||
|
||||
LLAres::NameInfoResponder::~NameInfoResponder()
|
||||
{
|
||||
}
|
||||
|
||||
void LLAres::NameInfoResponder::nameInfoResult(const char *node,
|
||||
const char *service)
|
||||
{
|
||||
LL_INFOS() << "LLAres::NameInfoResponder::nameInfoResult not implemented"
|
||||
<< LL_ENDL;
|
||||
}
|
||||
|
||||
void LLAres::NameInfoResponder::nameInfoError(int code)
|
||||
{
|
||||
LL_INFOS() << "LLAres::NameInfoResponder::nameInfoError " << code << ": "
|
||||
<< LLAres::strerror(code) << LL_ENDL;
|
||||
}
|
||||
|
||||
LLAres::QueryResponder::~QueryResponder()
|
||||
{
|
||||
}
|
||||
|
||||
void LLAres::QueryResponder::queryResult(const char *buf, size_t len)
|
||||
{
|
||||
LL_INFOS() << "LLAres::QueryResponder::queryResult not implemented"
|
||||
<< LL_ENDL;
|
||||
}
|
||||
|
||||
void LLAres::QueryResponder::queryError(int code)
|
||||
{
|
||||
LL_INFOS() << "LLAres::QueryResponder::queryError " << code << ": "
|
||||
<< LLAres::strerror(code) << LL_ENDL;
|
||||
}
|
||||
|
||||
LLAres::LLAres() :
|
||||
chan_(NULL),
|
||||
mInitSuccess(false)
|
||||
{
|
||||
if (ares_library_init( ARES_LIB_INIT_ALL ) != ARES_SUCCESS ||
|
||||
ares_init(&chan_) != ARES_SUCCESS)
|
||||
{
|
||||
LL_WARNS() << "Could not succesfully initialize ares!" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
mListener = boost::shared_ptr< LLAresListener >(new LLAresListener(this));
|
||||
|
||||
mInitSuccess = true;
|
||||
}
|
||||
|
||||
LLAres::~LLAres()
|
||||
{
|
||||
ares_destroy(chan_);
|
||||
ares_library_cleanup();
|
||||
}
|
||||
|
||||
void LLAres::cancel()
|
||||
{
|
||||
ares_cancel(chan_);
|
||||
}
|
||||
|
||||
static void host_callback_1_5(void *arg, int status, int timeouts,
|
||||
struct hostent *ent)
|
||||
{
|
||||
LLPointer<LLAres::HostResponder> *resp =
|
||||
(LLPointer<LLAres::HostResponder> *) arg;
|
||||
|
||||
if (status == ARES_SUCCESS)
|
||||
{
|
||||
(*resp)->hostResult(ent);
|
||||
} else {
|
||||
(*resp)->hostError(status);
|
||||
}
|
||||
|
||||
delete resp;
|
||||
}
|
||||
|
||||
#if ARES_VERSION_MAJOR == 1 && ARES_VERSION_MINOR == 4
|
||||
static void host_callback(void *arg, int status, struct hostent *ent)
|
||||
{
|
||||
host_callback_1_5(arg, status, 0, ent);
|
||||
}
|
||||
#else
|
||||
# define host_callback host_callback_1_5
|
||||
#endif
|
||||
|
||||
void LLAres::getHostByName(const char *name, HostResponder *resp,
|
||||
int family)
|
||||
{
|
||||
ares_gethostbyname(chan_, name, family, host_callback,
|
||||
new LLPointer<LLAres::HostResponder>(resp));
|
||||
}
|
||||
|
||||
void LLAres::getSrvRecords(const std::string &name, SrvResponder *resp)
|
||||
{
|
||||
search(name, RES_SRV, resp);
|
||||
}
|
||||
|
||||
void LLAres::rewriteURI(const std::string &uri, UriRewriteResponder *resp)
|
||||
{
|
||||
if (resp && uri.size())
|
||||
{
|
||||
LLURI* pURI = new LLURI(uri);
|
||||
|
||||
resp->mUri = *pURI;
|
||||
|
||||
delete pURI;
|
||||
|
||||
if (!resp->mUri.scheme().size() || !resp->mUri.hostName().size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//LL_INFOS() << "LLAres::rewriteURI (" << uri << ") search: '" << "_" + resp->mUri.scheme() + "._tcp." + resp->mUri.hostName() << "'" << LL_ENDL;
|
||||
|
||||
search("_" + resp->mUri.scheme() + "._tcp." + resp->mUri.hostName(), RES_SRV, resp);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
LLQueryResponder::LLQueryResponder()
|
||||
: LLAres::QueryResponder(),
|
||||
mResult(ARES_ENODATA),
|
||||
mType(RES_INVALID)
|
||||
{
|
||||
}
|
||||
|
||||
int LLQueryResponder::parseRR(const char *buf, size_t len, const char *&pos,
|
||||
LLPointer<LLDnsRecord> &r)
|
||||
{
|
||||
std::string rrname;
|
||||
size_t enclen;
|
||||
int ret;
|
||||
|
||||
// RR name.
|
||||
|
||||
ret = LLAres::expandName(pos, buf, len, rrname, enclen);
|
||||
if (ret != ARES_SUCCESS)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
pos += enclen;
|
||||
|
||||
if (pos + NS_RRFIXEDSZ > buf + len)
|
||||
{
|
||||
return ARES_EBADRESP;
|
||||
}
|
||||
|
||||
int rrtype = DNS_RR_TYPE(pos);
|
||||
int rrclass = DNS_RR_CLASS(pos);
|
||||
int rrttl = DNS_RR_TTL(pos);
|
||||
int rrlen = DNS_RR_LEN(pos);
|
||||
|
||||
if (rrclass != ns_c_in)
|
||||
{
|
||||
return ARES_EBADRESP;
|
||||
}
|
||||
|
||||
pos += NS_RRFIXEDSZ;
|
||||
|
||||
if (pos + rrlen > buf + len)
|
||||
{
|
||||
return ARES_EBADRESP;
|
||||
}
|
||||
|
||||
switch (rrtype)
|
||||
{
|
||||
case RES_A:
|
||||
r = new LLARecord(rrname, rrttl);
|
||||
break;
|
||||
case RES_NS:
|
||||
r = new LLNsRecord(rrname, rrttl);
|
||||
break;
|
||||
case RES_CNAME:
|
||||
r = new LLCnameRecord(rrname, rrttl);
|
||||
break;
|
||||
case RES_PTR:
|
||||
r = new LLPtrRecord(rrname, rrttl);
|
||||
break;
|
||||
case RES_AAAA:
|
||||
r = new LLAaaaRecord(rrname, rrttl);
|
||||
break;
|
||||
case RES_SRV:
|
||||
r = new LLSrvRecord(rrname, rrttl);
|
||||
break;
|
||||
default:
|
||||
LL_INFOS() << "LLQueryResponder::parseRR got unknown RR type " << rrtype
|
||||
<< LL_ENDL;
|
||||
return ARES_EBADRESP;
|
||||
}
|
||||
|
||||
ret = r->parse(buf, len, pos, rrlen);
|
||||
|
||||
if (ret == ARES_SUCCESS)
|
||||
{
|
||||
pos += rrlen;
|
||||
} else {
|
||||
r = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int LLQueryResponder::parseSection(const char *buf, size_t len,
|
||||
size_t count, const char *&pos,
|
||||
dns_rrs_t &rrs)
|
||||
{
|
||||
int ret = ARES_SUCCESS;
|
||||
|
||||
for (size_t i = 0; i < count; i++)
|
||||
{
|
||||
LLPointer<LLDnsRecord> r;
|
||||
ret = parseRR(buf, len, pos, r);
|
||||
if (ret != ARES_SUCCESS)
|
||||
{
|
||||
break;
|
||||
}
|
||||
rrs.push_back(r);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void LLQueryResponder::queryResult(const char *buf, size_t len)
|
||||
{
|
||||
const char *pos = buf;
|
||||
int qdcount = DNS_HEADER_QDCOUNT(pos);
|
||||
int ancount = DNS_HEADER_ANCOUNT(pos);
|
||||
int nscount = DNS_HEADER_NSCOUNT(pos);
|
||||
int arcount = DNS_HEADER_ARCOUNT(pos);
|
||||
int ret;
|
||||
|
||||
if (qdcount == 0 || ancount + nscount + arcount == 0)
|
||||
{
|
||||
ret = ARES_ENODATA;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
pos += NS_HFIXEDSZ;
|
||||
|
||||
for (int i = 0; i < qdcount; i++)
|
||||
{
|
||||
std::string ignore;
|
||||
size_t enclen;
|
||||
|
||||
ret = LLAres::expandName(pos, buf, len, i == 0 ? mQuery : ignore,
|
||||
enclen);
|
||||
if (ret != ARES_SUCCESS)
|
||||
{
|
||||
goto bail;
|
||||
}
|
||||
|
||||
pos += enclen;
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
int t = DNS_QUESTION_TYPE(pos);
|
||||
switch (t)
|
||||
{
|
||||
case RES_A:
|
||||
case RES_NS:
|
||||
case RES_CNAME:
|
||||
case RES_PTR:
|
||||
case RES_AAAA:
|
||||
case RES_SRV:
|
||||
mType = (LLResType) t;
|
||||
break;
|
||||
default:
|
||||
LL_INFOS() << "Cannot grok query type " << t << LL_ENDL;
|
||||
ret = ARES_EBADQUERY;
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
pos += NS_QFIXEDSZ;
|
||||
if (pos > buf + len)
|
||||
{
|
||||
ret = ARES_EBADRESP;
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
ret = parseSection(buf, len, ancount, pos, mAnswers);
|
||||
if (ret != ARES_SUCCESS)
|
||||
{
|
||||
goto bail;
|
||||
}
|
||||
|
||||
ret = parseSection(buf, len, nscount, pos, mAuthorities);
|
||||
if (ret != ARES_SUCCESS)
|
||||
{
|
||||
goto bail;
|
||||
}
|
||||
|
||||
ret = parseSection(buf, len, arcount, pos, mAdditional);
|
||||
|
||||
bail:
|
||||
mResult = ret;
|
||||
if (mResult == ARES_SUCCESS)
|
||||
{
|
||||
querySuccess();
|
||||
} else {
|
||||
queryError(mResult);
|
||||
}
|
||||
}
|
||||
|
||||
void LLQueryResponder::querySuccess()
|
||||
{
|
||||
LL_INFOS() << "LLQueryResponder::queryResult not implemented" << LL_ENDL;
|
||||
}
|
||||
|
||||
void LLAres::SrvResponder::querySuccess()
|
||||
{
|
||||
if (mType == RES_SRV)
|
||||
{
|
||||
srvResult(mAnswers);
|
||||
} else {
|
||||
srvError(ARES_EBADRESP);
|
||||
}
|
||||
}
|
||||
|
||||
void LLAres::SrvResponder::queryError(int code)
|
||||
{
|
||||
srvError(code);
|
||||
}
|
||||
|
||||
void LLAres::SrvResponder::srvResult(const dns_rrs_t &ents)
|
||||
{
|
||||
LL_INFOS() << "LLAres::SrvResponder::srvResult not implemented" << LL_ENDL;
|
||||
|
||||
for (size_t i = 0; i < ents.size(); i++)
|
||||
{
|
||||
const LLSrvRecord *s = (const LLSrvRecord *) ents[i].get();
|
||||
|
||||
LL_INFOS() << "[" << i << "] " << s->host() << ":" << s->port()
|
||||
<< " priority " << s->priority()
|
||||
<< " weight " << s->weight()
|
||||
<< LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
void LLAres::SrvResponder::srvError(int code)
|
||||
{
|
||||
LL_INFOS() << "LLAres::SrvResponder::srvError " << code << ": "
|
||||
<< LLAres::strerror(code) << LL_ENDL;
|
||||
}
|
||||
|
||||
static void nameinfo_callback_1_5(void *arg, int status, int timeouts,
|
||||
char *node, char *service)
|
||||
{
|
||||
LLPointer<LLAres::NameInfoResponder> *resp =
|
||||
(LLPointer<LLAres::NameInfoResponder> *) arg;
|
||||
|
||||
if (status == ARES_SUCCESS)
|
||||
{
|
||||
(*resp)->nameInfoResult(node, service);
|
||||
} else {
|
||||
(*resp)->nameInfoError(status);
|
||||
}
|
||||
|
||||
delete resp;
|
||||
}
|
||||
|
||||
#if ARES_VERSION_MAJOR == 1 && ARES_VERSION_MINOR == 4
|
||||
static void nameinfo_callback(void *arg, int status, char *node, char *service)
|
||||
{
|
||||
nameinfo_callback_1_5(arg, status, 0, node, service);
|
||||
}
|
||||
#else
|
||||
# define nameinfo_callback nameinfo_callback_1_5
|
||||
#endif
|
||||
|
||||
void LLAres::getNameInfo(const struct sockaddr &sa, socklen_t salen, int flags,
|
||||
NameInfoResponder *resp)
|
||||
{
|
||||
ares_getnameinfo(chan_, &sa, salen, flags, nameinfo_callback,
|
||||
new LLPointer<NameInfoResponder>(resp));
|
||||
}
|
||||
|
||||
static void search_callback_1_5(void *arg, int status, int timeouts,
|
||||
unsigned char *abuf, int alen)
|
||||
{
|
||||
LLPointer<LLAres::QueryResponder> *resp =
|
||||
(LLPointer<LLAres::QueryResponder> *) arg;
|
||||
|
||||
if (status == ARES_SUCCESS)
|
||||
{
|
||||
(*resp)->queryResult((const char *) abuf, alen);
|
||||
} else {
|
||||
(*resp)->queryError(status);
|
||||
}
|
||||
|
||||
delete resp;
|
||||
}
|
||||
|
||||
#if ARES_VERSION_MAJOR == 1 && ARES_VERSION_MINOR == 4
|
||||
static void search_callback(void *arg, int status, unsigned char *abuf,
|
||||
int alen)
|
||||
{
|
||||
search_callback_1_5(arg, status, 0, abuf, alen);
|
||||
}
|
||||
#else
|
||||
# define search_callback search_callback_1_5
|
||||
#endif
|
||||
|
||||
void LLAres::search(const std::string &query, LLResType type,
|
||||
QueryResponder *resp)
|
||||
{
|
||||
ares_search(chan_, query.c_str(), ns_c_in, type, search_callback,
|
||||
new LLPointer<QueryResponder>(resp));
|
||||
}
|
||||
|
||||
bool LLAres::process(U64 timeout)
|
||||
{
|
||||
if (!gAPRPoolp)
|
||||
{
|
||||
ll_init_apr();
|
||||
}
|
||||
|
||||
ares_socket_t socks[ARES_GETSOCK_MAXNUM];
|
||||
apr_pollfd_t aprFds[ARES_GETSOCK_MAXNUM];
|
||||
apr_int32_t nsds = 0;
|
||||
int nactive = 0;
|
||||
int bitmask;
|
||||
|
||||
bitmask = ares_getsock(chan_, socks, ARES_GETSOCK_MAXNUM);
|
||||
|
||||
if (bitmask == 0)
|
||||
{
|
||||
return nsds > 0;
|
||||
}
|
||||
|
||||
apr_status_t status;
|
||||
LLAPRPool pool;
|
||||
status = pool.getStatus() ;
|
||||
ll_apr_assert_status(status);
|
||||
|
||||
for (int i = 0; i < ARES_GETSOCK_MAXNUM; i++)
|
||||
{
|
||||
if (ARES_GETSOCK_READABLE(bitmask, i))
|
||||
{
|
||||
aprFds[nactive].reqevents = APR_POLLIN | APR_POLLERR;
|
||||
}
|
||||
else if (ARES_GETSOCK_WRITABLE(bitmask, i))
|
||||
{
|
||||
aprFds[nactive].reqevents = APR_POLLOUT | APR_POLLERR;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
apr_socket_t *aprSock = NULL;
|
||||
|
||||
status = apr_os_sock_put(&aprSock, (apr_os_sock_t *) &socks[i], pool.getAPRPool());
|
||||
if (status != APR_SUCCESS)
|
||||
{
|
||||
ll_apr_warn_status(status);
|
||||
return nsds > 0;
|
||||
}
|
||||
|
||||
aprFds[nactive].desc.s = aprSock;
|
||||
aprFds[nactive].desc_type = APR_POLL_SOCKET;
|
||||
aprFds[nactive].p = pool.getAPRPool();
|
||||
aprFds[nactive].rtnevents = 0;
|
||||
aprFds[nactive].client_data = &socks[i];
|
||||
|
||||
nactive++;
|
||||
}
|
||||
|
||||
if (nactive > 0)
|
||||
{
|
||||
status = apr_poll(aprFds, nactive, &nsds, timeout);
|
||||
|
||||
if (status != APR_SUCCESS && status != APR_TIMEUP)
|
||||
{
|
||||
ll_apr_warn_status(status);
|
||||
}
|
||||
|
||||
for (int i = 0; i < nactive; i++)
|
||||
{
|
||||
int evts = aprFds[i].rtnevents;
|
||||
int ifd = (evts & (APR_POLLIN | APR_POLLERR))
|
||||
? *((int *) aprFds[i].client_data) : ARES_SOCKET_BAD;
|
||||
int ofd = (evts & (APR_POLLOUT | APR_POLLERR))
|
||||
? *((int *) aprFds[i].client_data) : ARES_SOCKET_BAD;
|
||||
|
||||
ares_process_fd(chan_, ifd, ofd);
|
||||
}
|
||||
}
|
||||
|
||||
return nsds > 0;
|
||||
}
|
||||
|
||||
bool LLAres::processAll()
|
||||
{
|
||||
bool anyProcessed = false, ret;
|
||||
|
||||
do {
|
||||
timeval tv;
|
||||
|
||||
ret = ares_timeout(chan_, NULL, &tv) != NULL;
|
||||
|
||||
if (ret)
|
||||
{
|
||||
ret = process(tv.tv_sec * 1000000LL + tv.tv_usec);
|
||||
anyProcessed |= ret;
|
||||
}
|
||||
} while (ret);
|
||||
|
||||
return anyProcessed;
|
||||
}
|
||||
|
||||
int LLAres::expandName(const char *encoded, const char *abuf, size_t alen,
|
||||
std::string &s, size_t &enclen)
|
||||
{
|
||||
char *t;
|
||||
int ret;
|
||||
long e;
|
||||
|
||||
ret = ares_expand_name((const unsigned char *) encoded,
|
||||
(const unsigned char *) abuf, alen, &t, &e);
|
||||
if (ret == ARES_SUCCESS)
|
||||
{
|
||||
s.assign(t);
|
||||
enclen = e;
|
||||
ares_free_string(t);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char *LLAres::strerror(int code)
|
||||
{
|
||||
return ares_strerror(code);
|
||||
}
|
||||
|
||||
LLAres *gAres;
|
||||
|
||||
LLAres *ll_init_ares()
|
||||
{
|
||||
if (gAres == NULL)
|
||||
{
|
||||
gAres = new LLAres();
|
||||
}
|
||||
return gAres;
|
||||
}
|
||||
|
||||
void ll_cleanup_ares()
|
||||
{
|
||||
if (gAres != NULL)
|
||||
{
|
||||
delete gAres;
|
||||
gAres = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
LLDnsRecord::LLDnsRecord(LLResType type, const std::string &name,
|
||||
unsigned ttl)
|
||||
: LLRefCount(),
|
||||
mType(type),
|
||||
mName(name),
|
||||
mTTL(ttl)
|
||||
{
|
||||
}
|
||||
|
||||
LLHostRecord::LLHostRecord(LLResType type, const std::string &name,
|
||||
unsigned ttl)
|
||||
: LLDnsRecord(type, name, ttl)
|
||||
{
|
||||
}
|
||||
|
||||
int LLHostRecord::parse(const char *buf, size_t len, const char *pos,
|
||||
size_t rrlen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = LLAres::expandName(pos, buf, len, mHost);
|
||||
if (ret != ARES_SUCCESS)
|
||||
{
|
||||
goto bail;
|
||||
}
|
||||
|
||||
ret = ARES_SUCCESS;
|
||||
|
||||
bail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
LLCnameRecord::LLCnameRecord(const std::string &name, unsigned ttl)
|
||||
: LLHostRecord(RES_CNAME, name, ttl)
|
||||
{
|
||||
}
|
||||
|
||||
LLPtrRecord::LLPtrRecord(const std::string &name, unsigned ttl)
|
||||
: LLHostRecord(RES_PTR, name, ttl)
|
||||
{
|
||||
}
|
||||
|
||||
LLAddrRecord::LLAddrRecord(LLResType type, const std::string &name,
|
||||
unsigned ttl)
|
||||
: LLDnsRecord(type, name, ttl),
|
||||
|
||||
mSize(0)
|
||||
{
|
||||
}
|
||||
|
||||
LLARecord::LLARecord(const std::string &name, unsigned ttl)
|
||||
: LLAddrRecord(RES_A, name, ttl)
|
||||
{
|
||||
}
|
||||
|
||||
int LLARecord::parse(const char *buf, size_t len, const char *pos,
|
||||
size_t rrlen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (rrlen != sizeof(mSA.sin.sin_addr.s_addr))
|
||||
{
|
||||
ret = ARES_EBADRESP;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
memset(&mSA, 0, sizeof(mSA));
|
||||
memcpy(&mSA.sin.sin_addr.s_addr, pos, rrlen);
|
||||
mSA.sin.sin_family = AF_INET6;
|
||||
mSize = sizeof(mSA.sin);
|
||||
|
||||
ret = ARES_SUCCESS;
|
||||
|
||||
bail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
LLAaaaRecord::LLAaaaRecord(const std::string &name, unsigned ttl)
|
||||
: LLAddrRecord(RES_AAAA, name, ttl)
|
||||
{
|
||||
}
|
||||
|
||||
int LLAaaaRecord::parse(const char *buf, size_t len, const char *pos,
|
||||
size_t rrlen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (rrlen != sizeof(mSA.sin6.sin6_addr))
|
||||
{
|
||||
ret = ARES_EBADRESP;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
memset(&mSA, 0, sizeof(mSA));
|
||||
memcpy(&mSA.sin6.sin6_addr.s6_addr, pos, rrlen);
|
||||
mSA.sin6.sin6_family = AF_INET6;
|
||||
mSize = sizeof(mSA.sin6);
|
||||
|
||||
ret = ARES_SUCCESS;
|
||||
|
||||
bail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
LLSrvRecord::LLSrvRecord(const std::string &name, unsigned ttl)
|
||||
: LLHostRecord(RES_SRV, name, ttl),
|
||||
|
||||
mPriority(0),
|
||||
mWeight(0),
|
||||
mPort(0)
|
||||
{
|
||||
}
|
||||
|
||||
int LLSrvRecord::parse(const char *buf, size_t len, const char *pos,
|
||||
size_t rrlen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (rrlen < 6)
|
||||
{
|
||||
ret = ARES_EBADRESP;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
memcpy(&mPriority, pos, 2);
|
||||
memcpy(&mWeight, pos + 2, 2);
|
||||
memcpy(&mPort, pos + 4, 2);
|
||||
|
||||
mPriority = ntohs(mPriority);
|
||||
mWeight = ntohs(mWeight);
|
||||
mPort = ntohs(mPort);
|
||||
|
||||
ret = LLHostRecord::parse(buf, len, pos + 6, rrlen - 6);
|
||||
|
||||
bail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
LLNsRecord::LLNsRecord(const std::string &name, unsigned ttl)
|
||||
: LLHostRecord(RES_NS, name, ttl)
|
||||
{
|
||||
}
|
||||
|
||||
void LLAres::UriRewriteResponder::queryError(int code)
|
||||
{
|
||||
std::vector<std::string> uris;
|
||||
uris.push_back(mUri.asString());
|
||||
rewriteResult(uris);
|
||||
}
|
||||
|
||||
void LLAres::UriRewriteResponder::querySuccess()
|
||||
{
|
||||
std::vector<std::string> uris;
|
||||
|
||||
if (mType != RES_SRV)
|
||||
{
|
||||
goto bail;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < mAnswers.size(); i++)
|
||||
{
|
||||
const LLSrvRecord *r = (const LLSrvRecord *) mAnswers[i].get();
|
||||
|
||||
if (r->type() == RES_SRV)
|
||||
{
|
||||
// Check the domain in the response to ensure that it's
|
||||
// the same as the domain in the request, so that bad guys
|
||||
// can't forge responses that point to their own login
|
||||
// servers with their own certificates.
|
||||
|
||||
// Hard-coding the domain to check here is a bit of a
|
||||
// hack. Hoist it to an outer caller if anyone ever needs
|
||||
// this functionality on other domains.
|
||||
|
||||
static const std::string domain(".lindenlab.com");
|
||||
const std::string &host = r->host();
|
||||
|
||||
std::string::size_type s = host.find(domain) + domain.length();
|
||||
|
||||
if (s != host.length() && s != host.length() - 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
LLURI uri(mUri.scheme(),
|
||||
mUri.userName(),
|
||||
mUri.password(),
|
||||
r->host(),
|
||||
mUri.defaultPort() ? r->port() : mUri.hostPort(),
|
||||
mUri.escapedPath(),
|
||||
mUri.escapedQuery());
|
||||
uris.push_back(uri.asString());
|
||||
}
|
||||
}
|
||||
|
||||
if (!uris.empty())
|
||||
{
|
||||
goto done;
|
||||
}
|
||||
|
||||
bail:
|
||||
uris.push_back(mUri.asString());
|
||||
|
||||
done:
|
||||
rewriteResult(uris);
|
||||
}
|
||||
|
||||
void LLAres::UriRewriteResponder::rewriteResult(
|
||||
const std::vector<std::string> &uris)
|
||||
{
|
||||
LL_INFOS() << "LLAres::UriRewriteResponder::rewriteResult not implemented"
|
||||
<< LL_ENDL;
|
||||
|
||||
for (size_t i = 0; i < uris.size(); i++)
|
||||
{
|
||||
LL_INFOS() << "[" << i << "] " << uris[i] << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,583 +0,0 @@
|
|||
/**
|
||||
* @file llares.h
|
||||
* @author Bryan O'Sullivan
|
||||
* @date 2007-08-15
|
||||
* @brief Wrapper for asynchronous DNS lookups.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2007&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLARES_H
|
||||
#define LL_LLARES_H
|
||||
|
||||
#ifdef LL_WINDOWS
|
||||
// ares.h is broken on windows in that it depends on types defined in ws2tcpip.h
|
||||
// we need to include them first to work around it, but the headers issue warnings
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable:4996)
|
||||
# include <winsock2.h>
|
||||
# include <ws2tcpip.h>
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#ifdef LL_USESYSTEMLIBS
|
||||
# include <ares.h>
|
||||
#else
|
||||
# include <ares/ares.h>
|
||||
#endif
|
||||
|
||||
#include "llpointer.h"
|
||||
#include "llrefcount.h"
|
||||
#include "lluri.h"
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
class LLQueryResponder;
|
||||
class LLAresListener;
|
||||
|
||||
/**
|
||||
* @brief Supported DNS RR types.
|
||||
*/
|
||||
enum LLResType
|
||||
{
|
||||
RES_INVALID = 0, /**< Cookie. */
|
||||
RES_A = 1, /**< "A" record. IPv4 address. */
|
||||
RES_NS = 2, /**< "NS" record. Authoritative server. */
|
||||
RES_CNAME = 5, /**< "CNAME" record. Canonical name. */
|
||||
RES_PTR = 12, /**< "PTR" record. Domain name pointer. */
|
||||
RES_AAAA = 28, /**< "AAAA" record. IPv6 Address. */
|
||||
RES_SRV = 33, /**< "SRV" record. Server Selection. */
|
||||
RES_MAX = 65536 /**< Sentinel; RR types are 16 bits wide. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @class LLDnsRecord
|
||||
* @brief Base class for all DNS RR types.
|
||||
*/
|
||||
class LLDnsRecord : public LLRefCount
|
||||
{
|
||||
protected:
|
||||
friend class LLQueryResponder;
|
||||
|
||||
LLResType mType;
|
||||
std::string mName;
|
||||
unsigned mTTL;
|
||||
|
||||
virtual int parse(const char *buf, size_t len, const char *pos,
|
||||
size_t rrlen) = 0;
|
||||
|
||||
LLDnsRecord(LLResType type, const std::string &name, unsigned ttl);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Record name.
|
||||
*/
|
||||
const std::string &name() const { return mName; }
|
||||
|
||||
/**
|
||||
* @brief Time-to-live value, in seconds.
|
||||
*/
|
||||
unsigned ttl() const { return mTTL; }
|
||||
|
||||
/**
|
||||
* @brief RR type.
|
||||
*/
|
||||
LLResType type() const { return mType; }
|
||||
};
|
||||
|
||||
/**
|
||||
* @class LLAddrRecord
|
||||
* @brief Base class for address-related RRs.
|
||||
*/
|
||||
class LLAddrRecord : public LLDnsRecord
|
||||
{
|
||||
protected:
|
||||
friend class LLQueryResponder;
|
||||
|
||||
LLAddrRecord(LLResType type, const std::string &name, unsigned ttl);
|
||||
|
||||
union
|
||||
{
|
||||
sockaddr sa;
|
||||
sockaddr_in sin;
|
||||
sockaddr_in6 sin6;
|
||||
} mSA;
|
||||
|
||||
socklen_t mSize;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Generic socket address.
|
||||
*/
|
||||
const sockaddr &addr() const { return mSA.sa; }
|
||||
|
||||
/**
|
||||
* @brief Size of the socket structure.
|
||||
*/
|
||||
socklen_t size() const { return mSize; }
|
||||
};
|
||||
|
||||
/**
|
||||
* @class LLARecord
|
||||
* @brief A RR, for IPv4 addresses.
|
||||
*/
|
||||
class LLARecord : public LLAddrRecord
|
||||
{
|
||||
protected:
|
||||
friend class LLQueryResponder;
|
||||
|
||||
LLARecord(const std::string &name, unsigned ttl);
|
||||
|
||||
int parse(const char *buf, size_t len, const char *pos, size_t rrlen);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Socket address.
|
||||
*/
|
||||
const sockaddr_in &addr_in() const { return mSA.sin; }
|
||||
};
|
||||
|
||||
/**
|
||||
* @class LLAaaaRecord
|
||||
* @brief AAAA RR, for IPv6 addresses.
|
||||
*/
|
||||
class LLAaaaRecord : public LLAddrRecord
|
||||
{
|
||||
protected:
|
||||
friend class LLQueryResponder;
|
||||
|
||||
LLAaaaRecord(const std::string &name, unsigned ttl);
|
||||
|
||||
int parse(const char *buf, size_t len, const char *pos, size_t rrlen);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Socket address.
|
||||
*/
|
||||
const sockaddr_in6 &addr_in6() const { return mSA.sin6; }
|
||||
};
|
||||
|
||||
/**
|
||||
* @class LLHostRecord
|
||||
* @brief Base class for host-related RRs.
|
||||
*/
|
||||
class LLHostRecord : public LLDnsRecord
|
||||
{
|
||||
protected:
|
||||
LLHostRecord(LLResType type, const std::string &name, unsigned ttl);
|
||||
|
||||
int parse(const char *buf, size_t len, const char *pos, size_t rrlen);
|
||||
|
||||
std::string mHost;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Host name.
|
||||
*/
|
||||
const std::string &host() const { return mHost; }
|
||||
};
|
||||
|
||||
/**
|
||||
* @class LLCnameRecord
|
||||
* @brief CNAME RR.
|
||||
*/
|
||||
class LLCnameRecord : public LLHostRecord
|
||||
{
|
||||
protected:
|
||||
friend class LLQueryResponder;
|
||||
|
||||
LLCnameRecord(const std::string &name, unsigned ttl);
|
||||
};
|
||||
|
||||
/**
|
||||
* @class LLPtrRecord
|
||||
* @brief PTR RR.
|
||||
*/
|
||||
class LLPtrRecord : public LLHostRecord
|
||||
{
|
||||
protected:
|
||||
friend class LLQueryResponder;
|
||||
|
||||
LLPtrRecord(const std::string &name, unsigned ttl);
|
||||
};
|
||||
|
||||
/**
|
||||
* @class LLSrvRecord
|
||||
* @brief SRV RR.
|
||||
*/
|
||||
class LLSrvRecord : public LLHostRecord
|
||||
{
|
||||
protected:
|
||||
U16 mPriority;
|
||||
U16 mWeight;
|
||||
U16 mPort;
|
||||
|
||||
int parse(const char *buf, size_t len, const char *pos, size_t rrlen);
|
||||
|
||||
public:
|
||||
LLSrvRecord(const std::string &name, unsigned ttl);
|
||||
|
||||
/**
|
||||
* @brief Service priority.
|
||||
*/
|
||||
U16 priority() const { return mPriority; }
|
||||
|
||||
/**
|
||||
* @brief Service weight.
|
||||
*/
|
||||
U16 weight() const { return mWeight; }
|
||||
|
||||
/**
|
||||
* @brief Port number of service.
|
||||
*/
|
||||
U16 port() const { return mPort; }
|
||||
|
||||
/**
|
||||
* @brief Functor for sorting SRV records by priority.
|
||||
*/
|
||||
struct ComparePriorityLowest
|
||||
{
|
||||
bool operator()(const LLSrvRecord& lhs, const LLSrvRecord& rhs)
|
||||
{
|
||||
return lhs.mPriority < rhs.mPriority;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @class LLNsRecord
|
||||
* @brief NS RR.
|
||||
*/
|
||||
class LLNsRecord : public LLHostRecord
|
||||
{
|
||||
public:
|
||||
LLNsRecord(const std::string &name, unsigned ttl);
|
||||
};
|
||||
|
||||
class LLQueryResponder;
|
||||
|
||||
/**
|
||||
* @class LLAres
|
||||
* @brief Asynchronous address resolver.
|
||||
*/
|
||||
class LLAres
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @class HostResponder
|
||||
* @brief Base class for responding to hostname lookups.
|
||||
* @see LLAres::getHostByName
|
||||
*/
|
||||
class HostResponder : public LLRefCount
|
||||
{
|
||||
public:
|
||||
virtual ~HostResponder();
|
||||
|
||||
virtual void hostResult(const hostent *ent);
|
||||
virtual void hostError(int code);
|
||||
};
|
||||
|
||||
/**
|
||||
* @class NameInfoResponder
|
||||
* @brief Base class for responding to address lookups.
|
||||
* @see LLAres::getNameInfo
|
||||
*/
|
||||
class NameInfoResponder : public LLRefCount
|
||||
{
|
||||
public:
|
||||
virtual ~NameInfoResponder();
|
||||
|
||||
virtual void nameInfoResult(const char *node, const char *service);
|
||||
virtual void nameInfoError(int code);
|
||||
};
|
||||
|
||||
/**
|
||||
* @class QueryResponder
|
||||
* @brief Base class for responding to custom searches.
|
||||
* @see LLAres::search
|
||||
*/
|
||||
class QueryResponder : public LLRefCount
|
||||
{
|
||||
public:
|
||||
virtual ~QueryResponder();
|
||||
|
||||
virtual void queryResult(const char *buf, size_t len);
|
||||
virtual void queryError(int code);
|
||||
};
|
||||
|
||||
class SrvResponder;
|
||||
class UriRewriteResponder;
|
||||
|
||||
LLAres();
|
||||
|
||||
~LLAres();
|
||||
|
||||
/**
|
||||
* Cancel all outstanding requests. The error methods of the
|
||||
* corresponding responders will be called, with ARES_ETIMEOUT.
|
||||
*/
|
||||
void cancel();
|
||||
|
||||
/**
|
||||
* Look up the address of a host.
|
||||
*
|
||||
* @param name name of host to look up
|
||||
* @param resp responder to call with result
|
||||
* @param family AF_INET for IPv4 addresses, AF_INET6 for IPv6
|
||||
*/
|
||||
void getHostByName(const std::string &name, HostResponder *resp,
|
||||
int family = AF_INET) {
|
||||
getHostByName(name.c_str(), resp, family);
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up the address of a host.
|
||||
*
|
||||
* @param name name of host to look up
|
||||
* @param resp responder to call with result
|
||||
* @param family AF_INET for IPv4 addresses, AF_INET6 for IPv6
|
||||
*/
|
||||
void getHostByName(const char *name, HostResponder *resp,
|
||||
int family = PF_INET);
|
||||
|
||||
/**
|
||||
* Look up the name associated with a socket address.
|
||||
*
|
||||
* @param sa socket address to look up
|
||||
* @param salen size of socket address
|
||||
* @param flags flags to use
|
||||
* @param resp responder to call with result
|
||||
*/
|
||||
void getNameInfo(const struct sockaddr &sa, socklen_t salen, int flags,
|
||||
NameInfoResponder *resp);
|
||||
|
||||
/**
|
||||
* Look up SRV (service location) records for a service name.
|
||||
*
|
||||
* @param name service name (e.g. "_https._tcp.login.agni.lindenlab.com")
|
||||
* @param resp responder to call with result
|
||||
*/
|
||||
void getSrvRecords(const std::string &name, SrvResponder *resp);
|
||||
|
||||
/**
|
||||
* Rewrite a URI, using SRV (service location) records for its
|
||||
* protocol if available. If no SRV records are published, the
|
||||
* existing URI is handed to the responder.
|
||||
*
|
||||
* @param uri URI to rewrite
|
||||
* @param resp responder to call with result
|
||||
*/
|
||||
void rewriteURI(const std::string &uri,
|
||||
UriRewriteResponder *resp);
|
||||
|
||||
/**
|
||||
* Start a custom search.
|
||||
*
|
||||
* @param query query to make
|
||||
* @param type type of query to perform
|
||||
* @param resp responder to call with result
|
||||
*/
|
||||
void search(const std::string &query, LLResType type,
|
||||
QueryResponder *resp);
|
||||
|
||||
/**
|
||||
* Process any outstanding queries. This method takes an optional
|
||||
* timeout parameter (specified in microseconds). If provided, it
|
||||
* will block the calling thread for that length of time to await
|
||||
* possible responses. A timeout of zero will return immediately
|
||||
* if there are no responses or timeouts to process.
|
||||
*
|
||||
* @param timeoutUsecs number of microseconds to block before timing out
|
||||
* @return whether any responses were processed
|
||||
*/
|
||||
bool process(U64 timeoutUsecs = 0);
|
||||
|
||||
/**
|
||||
* Process all outstanding queries, blocking the calling thread
|
||||
* until all have either been responded to or timed out.
|
||||
*
|
||||
* @return whether any responses were processed
|
||||
*/
|
||||
bool processAll();
|
||||
|
||||
/**
|
||||
* Expand a DNS-encoded compressed string into a normal string.
|
||||
*
|
||||
* @param encoded the encoded name (null-terminated)
|
||||
* @param abuf the response buffer in which the string is embedded
|
||||
* @param alen the length of the response buffer
|
||||
* @param s the string into which to place the result
|
||||
* @return ARES_SUCCESS on success, otherwise an error indicator
|
||||
*/
|
||||
static int expandName(const char *encoded, const char *abuf, size_t alen,
|
||||
std::string &s) {
|
||||
size_t ignore;
|
||||
return expandName(encoded, abuf, alen, s, ignore);
|
||||
}
|
||||
|
||||
static int expandName(const char *encoded, const char *abuf, size_t alen,
|
||||
std::string &s, size_t &enclen);
|
||||
|
||||
/**
|
||||
* Return a string describing an error code.
|
||||
*/
|
||||
static const char *strerror(int code);
|
||||
|
||||
bool isInitialized(void) { return mInitSuccess; }
|
||||
|
||||
protected:
|
||||
ares_channel chan_;
|
||||
bool mInitSuccess;
|
||||
// boost::scoped_ptr would actually fit the requirement better, but it
|
||||
// can't handle incomplete types as boost::shared_ptr can.
|
||||
boost::shared_ptr<LLAresListener> mListener;
|
||||
};
|
||||
|
||||
/**
|
||||
* An ordered collection of DNS resource records.
|
||||
*/
|
||||
typedef std::vector<LLPointer<LLDnsRecord> > dns_rrs_t;
|
||||
|
||||
/**
|
||||
* @class LLQueryResponder
|
||||
* @brief Base class for friendly handling of DNS query responses.
|
||||
*
|
||||
* This class parses a DNS response and represents it in a friendly
|
||||
* manner.
|
||||
*
|
||||
* @see LLDnsRecord
|
||||
* @see LLARecord
|
||||
* @see LLNsRecord
|
||||
* @see LLCnameRecord
|
||||
* @see LLPtrRecord
|
||||
* @see LLAaaaRecord
|
||||
* @see LLSrvRecord
|
||||
*/
|
||||
class LLQueryResponder : public LLAres::QueryResponder
|
||||
{
|
||||
protected:
|
||||
int mResult;
|
||||
std::string mQuery;
|
||||
LLResType mType;
|
||||
|
||||
dns_rrs_t mAnswers;
|
||||
dns_rrs_t mAuthorities;
|
||||
dns_rrs_t mAdditional;
|
||||
|
||||
/**
|
||||
* Parse a single RR.
|
||||
*/
|
||||
int parseRR(const char *buf, size_t len, const char *&pos,
|
||||
LLPointer<LLDnsRecord> &r);
|
||||
/**
|
||||
* Parse one section of a response.
|
||||
*/
|
||||
int parseSection(const char *buf, size_t len,
|
||||
size_t count, const char *& pos, dns_rrs_t &rrs);
|
||||
|
||||
void queryResult(const char *buf, size_t len);
|
||||
virtual void querySuccess();
|
||||
|
||||
public:
|
||||
LLQueryResponder();
|
||||
|
||||
/**
|
||||
* Indicate whether the response could be parsed successfully.
|
||||
*/
|
||||
bool valid() const { return mResult == ARES_SUCCESS; }
|
||||
|
||||
/**
|
||||
* The more detailed result of parsing the response.
|
||||
*/
|
||||
int result() const { return mResult; }
|
||||
|
||||
/**
|
||||
* Return the query embedded in the response.
|
||||
*/
|
||||
const std::string &query() const { return mQuery; }
|
||||
|
||||
/**
|
||||
* Return the contents of the "answers" section of the response.
|
||||
*/
|
||||
const dns_rrs_t &answers() const { return mAnswers; }
|
||||
|
||||
/**
|
||||
* Return the contents of the "authorities" section of the
|
||||
* response.
|
||||
*/
|
||||
const dns_rrs_t &authorities() const { return mAuthorities; }
|
||||
|
||||
/**
|
||||
* Return the contents of the "additional records" section of the
|
||||
* response.
|
||||
*/
|
||||
const dns_rrs_t &additional() const { return mAdditional; }
|
||||
};
|
||||
|
||||
/**
|
||||
* @class LLAres::SrvResponder
|
||||
* @brief Class for handling SRV query responses.
|
||||
*/
|
||||
class LLAres::SrvResponder : public LLQueryResponder
|
||||
{
|
||||
public:
|
||||
friend void LLAres::getSrvRecords(const std::string &name,
|
||||
SrvResponder *resp);
|
||||
void querySuccess();
|
||||
void queryError(int code);
|
||||
|
||||
virtual void srvResult(const dns_rrs_t &ents);
|
||||
virtual void srvError(int code);
|
||||
};
|
||||
|
||||
/**
|
||||
* @class LLAres::UriRewriteResponder
|
||||
* @brief Class for handling URI rewrites based on SRV records.
|
||||
*/
|
||||
class LLAres::UriRewriteResponder : public LLQueryResponder
|
||||
{
|
||||
protected:
|
||||
LLURI mUri;
|
||||
|
||||
public:
|
||||
friend void LLAres::rewriteURI(const std::string &uri,
|
||||
UriRewriteResponder *resp);
|
||||
void querySuccess();
|
||||
void queryError(int code);
|
||||
|
||||
virtual void rewriteResult(const std::vector<std::string> &uris);
|
||||
};
|
||||
|
||||
/**
|
||||
* Singleton responder.
|
||||
*/
|
||||
extern LLAres *gAres;
|
||||
|
||||
/**
|
||||
* Set up the singleton responder. It's safe to call this more than
|
||||
* once from within a single thread, but this function is not
|
||||
* thread safe.
|
||||
*/
|
||||
extern LLAres *ll_init_ares();
|
||||
extern void ll_cleanup_ares();
|
||||
|
||||
#endif // LL_LLARES_H
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
/**
|
||||
* @file llareslistener.cpp
|
||||
* @author Nat Goodspeed
|
||||
* @date 2009-03-18
|
||||
* @brief Implementation for llareslistener.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
// Precompiled header
|
||||
#include "linden_common.h"
|
||||
// associated header
|
||||
#include "llareslistener.h"
|
||||
// STL headers
|
||||
// std headers
|
||||
// external library headers
|
||||
// other Linden headers
|
||||
#include "llares.h"
|
||||
#include "llerror.h"
|
||||
#include "llevents.h"
|
||||
#include "llsdutil.h"
|
||||
|
||||
LLAresListener::LLAresListener(LLAres* llares):
|
||||
LLEventAPI("LLAres",
|
||||
"LLAres listener to request DNS operations"),
|
||||
mAres(llares)
|
||||
{
|
||||
// add() every method we want to be able to invoke via this event API.
|
||||
// Optional last parameter validates expected LLSD request structure.
|
||||
add("rewriteURI",
|
||||
"Given [\"uri\"], return on [\"reply\"] an array of alternative URIs.\n"
|
||||
"On failure, returns an array containing only the original URI, so\n"
|
||||
"failure case can be processed like success case.",
|
||||
&LLAresListener::rewriteURI,
|
||||
LLSD().with("uri", LLSD()).with("reply", LLSD()));
|
||||
}
|
||||
|
||||
/// This UriRewriteResponder subclass packages returned URIs as an LLSD
|
||||
/// array to send back to the requester.
|
||||
class UriRewriteResponder: public LLAres::UriRewriteResponder
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Specify the request, containing the event pump name on which to send
|
||||
* the reply.
|
||||
*/
|
||||
UriRewriteResponder(const LLSD& request):
|
||||
mReqID(request),
|
||||
mPumpName(request["reply"])
|
||||
{}
|
||||
|
||||
/// Called by base class with results. This is called in both the
|
||||
/// success and error cases. On error, the calling logic passes the
|
||||
/// original URI.
|
||||
virtual void rewriteResult(const std::vector<std::string>& uris)
|
||||
{
|
||||
LLSD result;
|
||||
for (std::vector<std::string>::const_iterator ui(uris.begin()), uend(uris.end());
|
||||
ui != uend; ++ui)
|
||||
{
|
||||
result.append(*ui);
|
||||
}
|
||||
// This call knows enough to avoid trying to insert a map key into an
|
||||
// LLSD array. It's there so that if, for any reason, we ever decide
|
||||
// to change the response from array to map, it will Just Start Working.
|
||||
mReqID.stamp(result);
|
||||
LLEventPumps::instance().obtain(mPumpName).post(result);
|
||||
}
|
||||
|
||||
private:
|
||||
LLReqID mReqID;
|
||||
const std::string mPumpName;
|
||||
};
|
||||
|
||||
void LLAresListener::rewriteURI(const LLSD& data)
|
||||
{
|
||||
if (mAres)
|
||||
{
|
||||
mAres->rewriteURI(data["uri"], new UriRewriteResponder(data));
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_INFOS() << "LLAresListener::rewriteURI requested without Ares present. Ignoring: " << data << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
/**
|
||||
* @file llareslistener.h
|
||||
* @author Nat Goodspeed
|
||||
* @date 2009-03-18
|
||||
* @brief LLEventPump API for LLAres. This header doesn't actually define the
|
||||
* API; the API is defined by the pump name on which this class
|
||||
* listens, and by the expected content of LLSD it receives.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#if ! defined(LL_LLARESLISTENER_H)
|
||||
#define LL_LLARESLISTENER_H
|
||||
|
||||
#include "lleventapi.h"
|
||||
|
||||
class LLAres;
|
||||
class LLSD;
|
||||
|
||||
/// Listen on an LLEventPump with specified name for LLAres request events.
|
||||
class LLAresListener: public LLEventAPI
|
||||
{
|
||||
public:
|
||||
/// Bind the LLAres instance to use (e.g. gAres)
|
||||
LLAresListener(LLAres* llares);
|
||||
|
||||
private:
|
||||
/// command["op"] == "rewriteURI"
|
||||
void rewriteURI(const LLSD& data);
|
||||
|
||||
LLAres* mAres;
|
||||
};
|
||||
|
||||
#endif /* ! defined(LL_LLARESLISTENER_H) */
|
||||
|
|
@ -57,7 +57,6 @@
|
|||
#include "llfocusmgr.h"
|
||||
#include "llviewerjoystick.h"
|
||||
#include "llallocator.h"
|
||||
#include "llares.h"
|
||||
#include "llcalc.h"
|
||||
#include "llconversationlog.h"
|
||||
#include "lldxhardware.h"
|
||||
|
|
@ -1283,7 +1282,6 @@ static LLTrace::BlockTimerStatHandle FTM_LFS("LFS Thread");
|
|||
static LLTrace::BlockTimerStatHandle FTM_PAUSE_THREADS("Pause Threads");
|
||||
static LLTrace::BlockTimerStatHandle FTM_IDLE("Idle");
|
||||
static LLTrace::BlockTimerStatHandle FTM_PUMP("Pump");
|
||||
static LLTrace::BlockTimerStatHandle FTM_PUMP_ARES("Ares");
|
||||
static LLTrace::BlockTimerStatHandle FTM_PUMP_SERVICE("Service");
|
||||
static LLTrace::BlockTimerStatHandle FTM_SERVICE_CALLBACK("Callback");
|
||||
static LLTrace::BlockTimerStatHandle FTM_AGENT_AUTOPILOT("Autopilot");
|
||||
|
|
@ -1425,26 +1423,6 @@ bool LLAppViewer::mainLoop()
|
|||
LL_RECORD_BLOCK_TIME(FTM_IDLE);
|
||||
idle();
|
||||
|
||||
if (gAres != NULL && gAres->isInitialized())
|
||||
{
|
||||
pingMainloopTimeout("Main:ServicePump");
|
||||
LL_RECORD_BLOCK_TIME(FTM_PUMP);
|
||||
{
|
||||
LL_RECORD_BLOCK_TIME(FTM_PUMP_ARES);
|
||||
gAres->process();
|
||||
}
|
||||
{
|
||||
LL_RECORD_BLOCK_TIME(FTM_PUMP_SERVICE);
|
||||
// this pump is necessary to make the login screen show up
|
||||
gServicePump->pump();
|
||||
|
||||
{
|
||||
LL_RECORD_BLOCK_TIME(FTM_SERVICE_CALLBACK);
|
||||
gServicePump->callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resumeMainloopTimeout();
|
||||
}
|
||||
|
||||
|
|
@ -2014,9 +1992,6 @@ bool LLAppViewer::cleanup()
|
|||
// Non-LLCurl libcurl library
|
||||
mAppCoreHttp.cleanup();
|
||||
|
||||
// NOTE The following call is not thread safe.
|
||||
ll_cleanup_ares();
|
||||
|
||||
LLFilePickerThread::cleanupClass();
|
||||
|
||||
//MUST happen AFTER LLCurl::cleanupClass
|
||||
|
|
|
|||
|
|
@ -46,7 +46,6 @@
|
|||
#include "llaudioengine_openal.h"
|
||||
#endif
|
||||
|
||||
#include "llares.h"
|
||||
#include "llavatarnamecache.h"
|
||||
#include "llexperiencecache.h"
|
||||
#include "lllandmark.h"
|
||||
|
|
@ -444,13 +443,6 @@ bool idle_startup()
|
|||
// Load the throttle settings
|
||||
gViewerThrottle.load();
|
||||
|
||||
if (ll_init_ares() == NULL || !gAres->isInitialized())
|
||||
{
|
||||
std::string diagnostic = "Could not start address resolution system";
|
||||
LL_WARNS("AppInit") << diagnostic << LL_ENDL;
|
||||
LLAppViewer::instance()->earlyExit("LoginFailedNoNetwork", LLSD().with("DIAGNOSTIC", diagnostic));
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize messaging system
|
||||
//
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ private:
|
|||
|
||||
// In a coroutine's top-level function args, do NOT NOT NOT accept
|
||||
// references (const or otherwise) to anything! Pass by value only!
|
||||
void login_(std::string uri, LLSD credentials);
|
||||
void loginCoro(std::string uri, LLSD credentials);
|
||||
|
||||
LLEventStream mPump;
|
||||
LLSD mAuthResponse, mValidAuthResponse;
|
||||
|
|
@ -122,11 +122,11 @@ void LLLogin::Impl::connect(const std::string& uri, const LLSD& login_params)
|
|||
// its first wait; at that point, return here.
|
||||
std::string coroname =
|
||||
LLCoros::instance().launch("LLLogin::Impl::login_",
|
||||
boost::bind(&Impl::login_, this, uri, login_params));
|
||||
boost::bind(&Impl::loginCoro, this, uri, login_params));
|
||||
LL_DEBUGS("LLLogin") << " connected with uri '" << uri << "', login_params " << login_params << LL_ENDL;
|
||||
}
|
||||
|
||||
void LLLogin::Impl::login_(std::string uri, LLSD login_params)
|
||||
void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
@ -143,43 +143,6 @@ void LLLogin::Impl::login_(std::string uri, LLSD login_params)
|
|||
LLEventStream replyPump("SRVreply", true);
|
||||
// Should be an array of one or more uri strings.
|
||||
|
||||
LLSD rewrittenURIs;
|
||||
{
|
||||
LLEventTimeout filter(replyPump);
|
||||
sendProgressEvent("offline", "srvrequest");
|
||||
|
||||
// Request SRV record.
|
||||
LL_DEBUGS("LLLogin") << "Requesting SRV record from " << uri << LL_ENDL;
|
||||
|
||||
// *NOTE:Mani - Completely arbitrary default timeout value for SRV request.
|
||||
F32 seconds_to_timeout = 5.0f;
|
||||
if(login_params.has("cfg_srv_timeout"))
|
||||
{
|
||||
seconds_to_timeout = login_params["cfg_srv_timeout"].asReal();
|
||||
}
|
||||
|
||||
// If the SRV request times out (e.g. EXT-3934), simulate response: an
|
||||
// array containing our original URI.
|
||||
LLSD fakeResponse(LLSD::emptyArray());
|
||||
fakeResponse.append(uri);
|
||||
filter.eventAfter(seconds_to_timeout, fakeResponse);
|
||||
|
||||
std::string srv_pump_name = "LLAres";
|
||||
if(login_params.has("cfg_srv_pump"))
|
||||
{
|
||||
srv_pump_name = login_params["cfg_srv_pump"].asString();
|
||||
}
|
||||
|
||||
// Make request
|
||||
LLSD request;
|
||||
request["op"] = "rewriteURI";
|
||||
request["uri"] = uri;
|
||||
request["reply"] = replyPump.getName();
|
||||
rewrittenURIs = llcoro::postAndSuspend(request, srv_pump_name, filter);
|
||||
// EXP-772: If rewrittenURIs fail, try original URI as a fallback.
|
||||
rewrittenURIs.append(uri);
|
||||
} // we no longer need the filter
|
||||
|
||||
LLEventPump& xmlrpcPump(LLEventPumps::instance().obtain("LLXMLRPCTransaction"));
|
||||
// EXT-4193: use a DIFFERENT reply pump than for the SRV request. We used
|
||||
// to share them -- but the EXT-3934 fix made it possible for an abandoned
|
||||
|
|
@ -190,107 +153,103 @@ void LLLogin::Impl::login_(std::string uri, LLSD login_params)
|
|||
// Because of possible redirect responses, we may make more than one
|
||||
// attempt per rewrittenURIs entry.
|
||||
LLSD::Integer attempts = 0;
|
||||
for (LLSD::array_const_iterator urit(rewrittenURIs.beginArray()),
|
||||
urend(rewrittenURIs.endArray());
|
||||
urit != urend; ++urit)
|
||||
|
||||
LLSD request(login_params);
|
||||
request["reply"] = loginReplyPump.getName();
|
||||
request["uri"] = uri;
|
||||
std::string status;
|
||||
|
||||
// Loop back to here if login attempt redirects to a different
|
||||
// request["uri"]
|
||||
for (;;)
|
||||
{
|
||||
LLSD request(login_params);
|
||||
request["reply"] = loginReplyPump.getName();
|
||||
request["uri"] = *urit;
|
||||
std::string status;
|
||||
|
||||
// Loop back to here if login attempt redirects to a different
|
||||
// request["uri"]
|
||||
for (;;)
|
||||
{
|
||||
++attempts;
|
||||
LLSD progress_data;
|
||||
progress_data["attempt"] = attempts;
|
||||
progress_data["request"] = request;
|
||||
if(progress_data["request"].has("params")
|
||||
&& progress_data["request"]["params"].has("passwd"))
|
||||
{
|
||||
progress_data["request"]["params"]["passwd"] = "*******";
|
||||
}
|
||||
sendProgressEvent("offline", "authenticating", progress_data);
|
||||
|
||||
// We expect zero or more "Downloading" status events, followed by
|
||||
// exactly one event with some other status. Use postAndSuspend() the
|
||||
// first time, because -- at least in unit-test land -- it's
|
||||
// possible for the reply to arrive before the post() call
|
||||
// returns. Subsequent responses, of course, must be awaited
|
||||
// without posting again.
|
||||
for (mAuthResponse = validateResponse(loginReplyPump.getName(),
|
||||
llcoro::postAndSuspend(request, xmlrpcPump, loginReplyPump, "reply"));
|
||||
mAuthResponse["status"].asString() == "Downloading";
|
||||
mAuthResponse = validateResponse(loginReplyPump.getName(),
|
||||
llcoro::suspendUntilEventOn(loginReplyPump)))
|
||||
{
|
||||
// Still Downloading -- send progress update.
|
||||
sendProgressEvent("offline", "downloading");
|
||||
}
|
||||
|
||||
LL_DEBUGS("LLLogin") << "Auth Response: " << mAuthResponse << LL_ENDL;
|
||||
status = mAuthResponse["status"].asString();
|
||||
|
||||
// Okay, we've received our final status event for this
|
||||
// request. Unless we got a redirect response, break the retry
|
||||
// loop for the current rewrittenURIs entry.
|
||||
if (!(status == "Complete" &&
|
||||
mAuthResponse["responses"]["login"].asString() == "indeterminate"))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
sendProgressEvent("offline", "indeterminate", mAuthResponse["responses"]);
|
||||
|
||||
// Here the login service at the current URI is redirecting us
|
||||
// to some other URI ("indeterminate" -- why not "redirect"?).
|
||||
// The response should contain another uri to try, with its
|
||||
// own auth method.
|
||||
request["uri"] = mAuthResponse["responses"]["next_url"].asString();
|
||||
request["method"] = mAuthResponse["responses"]["next_method"].asString();
|
||||
} // loop back to try the redirected URI
|
||||
|
||||
// Here we're done with redirects for the current rewrittenURIs
|
||||
// entry.
|
||||
if (status == "Complete")
|
||||
{
|
||||
// StatusComplete does not imply auth success. Check the
|
||||
// actual outcome of the request. We've already handled the
|
||||
// "indeterminate" case in the loop above.
|
||||
if (mAuthResponse["responses"]["login"].asString() == "true")
|
||||
{
|
||||
sendProgressEvent("online", "connect", mAuthResponse["responses"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
sendProgressEvent("offline", "fail.login", mAuthResponse["responses"]);
|
||||
}
|
||||
return; // Done!
|
||||
}
|
||||
|
||||
/* Sometimes we end with "Started" here. Slightly slow server?
|
||||
* Seems to be ok to just skip it. Otherwise we'd error out and crash in the if below.
|
||||
*/
|
||||
if( status == "Started")
|
||||
++attempts;
|
||||
LLSD progress_data;
|
||||
progress_data["attempt"] = attempts;
|
||||
progress_data["request"] = request;
|
||||
if(progress_data["request"].has("params")
|
||||
&& progress_data["request"]["params"].has("passwd"))
|
||||
{
|
||||
LL_DEBUGS("LLLogin") << mAuthResponse << LL_ENDL;
|
||||
continue;
|
||||
progress_data["request"]["params"]["passwd"] = "*******";
|
||||
}
|
||||
sendProgressEvent("offline", "authenticating", progress_data);
|
||||
|
||||
// If we don't recognize status at all, trouble
|
||||
if (! (status == "CURLError"
|
||||
|| status == "XMLRPCError"
|
||||
|| status == "OtherError"))
|
||||
// We expect zero or more "Downloading" status events, followed by
|
||||
// exactly one event with some other status. Use postAndSuspend() the
|
||||
// first time, because -- at least in unit-test land -- it's
|
||||
// possible for the reply to arrive before the post() call
|
||||
// returns. Subsequent responses, of course, must be awaited
|
||||
// without posting again.
|
||||
for (mAuthResponse = validateResponse(loginReplyPump.getName(),
|
||||
llcoro::postAndSuspend(request, xmlrpcPump, loginReplyPump, "reply"));
|
||||
mAuthResponse["status"].asString() == "Downloading";
|
||||
mAuthResponse = validateResponse(loginReplyPump.getName(),
|
||||
llcoro::suspendUntilEventOn(loginReplyPump)))
|
||||
{
|
||||
LL_ERRS("LLLogin") << "Unexpected status from " << xmlrpcPump.getName() << " pump: "
|
||||
<< mAuthResponse << LL_ENDL;
|
||||
return;
|
||||
// Still Downloading -- send progress update.
|
||||
sendProgressEvent("offline", "downloading");
|
||||
}
|
||||
|
||||
LL_DEBUGS("LLLogin") << "Auth Response: " << mAuthResponse << LL_ENDL;
|
||||
status = mAuthResponse["status"].asString();
|
||||
|
||||
// Okay, we've received our final status event for this
|
||||
// request. Unless we got a redirect response, break the retry
|
||||
// loop for the current rewrittenURIs entry.
|
||||
if (!(status == "Complete" &&
|
||||
mAuthResponse["responses"]["login"].asString() == "indeterminate"))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Here status IS one of the errors tested above.
|
||||
} // Retry if there are any more rewrittenURIs.
|
||||
sendProgressEvent("offline", "indeterminate", mAuthResponse["responses"]);
|
||||
|
||||
// Here the login service at the current URI is redirecting us
|
||||
// to some other URI ("indeterminate" -- why not "redirect"?).
|
||||
// The response should contain another uri to try, with its
|
||||
// own auth method.
|
||||
request["uri"] = mAuthResponse["responses"]["next_url"].asString();
|
||||
request["method"] = mAuthResponse["responses"]["next_method"].asString();
|
||||
} // loop back to try the redirected URI
|
||||
|
||||
// Here we're done with redirects for the current rewrittenURIs
|
||||
// entry.
|
||||
if (status == "Complete")
|
||||
{
|
||||
// StatusComplete does not imply auth success. Check the
|
||||
// actual outcome of the request. We've already handled the
|
||||
// "indeterminate" case in the loop above.
|
||||
if (mAuthResponse["responses"]["login"].asString() == "true")
|
||||
{
|
||||
sendProgressEvent("online", "connect", mAuthResponse["responses"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
sendProgressEvent("offline", "fail.login", mAuthResponse["responses"]);
|
||||
}
|
||||
return; // Done!
|
||||
}
|
||||
|
||||
// /* Sometimes we end with "Started" here. Slightly slow server?
|
||||
// * Seems to be ok to just skip it. Otherwise we'd error out and crash in the if below.
|
||||
// */
|
||||
// if( status == "Started")
|
||||
// {
|
||||
// LL_DEBUGS("LLLogin") << mAuthResponse << LL_ENDL;
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// If we don't recognize status at all, trouble
|
||||
if (! (status == "CURLError"
|
||||
|| status == "XMLRPCError"
|
||||
|| status == "OtherError"))
|
||||
{
|
||||
LL_ERRS("LLLogin") << "Unexpected status from " << xmlrpcPump.getName() << " pump: "
|
||||
<< mAuthResponse << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
// Here status IS one of the errors tested above.
|
||||
|
||||
// Here we got through all the rewrittenURIs without succeeding. Tell
|
||||
// caller this didn't work out so well. Of course, the only failure data
|
||||
|
|
|
|||
|
|
@ -96,61 +96,6 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class LLAresListener: public LLEventTrackable
|
||||
{
|
||||
std::string mName;
|
||||
LLSD mEvent;
|
||||
bool mImmediateResponse;
|
||||
bool mMultipleURIResponse;
|
||||
Debug mDebug;
|
||||
|
||||
public:
|
||||
LLAresListener(const std::string& name,
|
||||
bool i = false,
|
||||
bool m = false
|
||||
) :
|
||||
mName(name),
|
||||
mImmediateResponse(i),
|
||||
mMultipleURIResponse(m),
|
||||
mDebug(stringize(*this))
|
||||
{}
|
||||
|
||||
bool handle_event(const LLSD& event)
|
||||
{
|
||||
mDebug(STRINGIZE("LLAresListener called!: " << event));
|
||||
mEvent = event;
|
||||
if(mImmediateResponse)
|
||||
{
|
||||
sendReply();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void sendReply()
|
||||
{
|
||||
if(mEvent["op"].asString() == "rewriteURI")
|
||||
{
|
||||
LLSD result;
|
||||
if(mMultipleURIResponse)
|
||||
{
|
||||
result.append(LLSD("login.foo.com"));
|
||||
}
|
||||
result.append(mEvent["uri"]);
|
||||
LLEventPumps::instance().obtain(mEvent["reply"]).post(result);
|
||||
}
|
||||
}
|
||||
|
||||
LLBoundListener listenTo(LLEventPump& pump)
|
||||
{
|
||||
return pump.listen(mName, boost::bind(&LLAresListener::handle_event, this, _1));
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& out, const LLAresListener& listener)
|
||||
{
|
||||
return out << "LLAresListener(" << listener.mName << ')';
|
||||
}
|
||||
};
|
||||
|
||||
class LLXMLRPCListener: public LLEventTrackable
|
||||
{
|
||||
std::string mName;
|
||||
|
|
@ -232,16 +177,12 @@ namespace tut
|
|||
void llviewerlogin_object::test<1>()
|
||||
{
|
||||
DEBUG;
|
||||
// Testing login with immediate responses from Ares and XMLPRC
|
||||
// The response from both requests will come before the post request exits.
|
||||
// Testing login with an immediate response from XMLPRC
|
||||
// The response will come before the post request exits.
|
||||
// This tests an edge case of the login state handling.
|
||||
LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
|
||||
LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump
|
||||
|
||||
bool respond_immediately = true;
|
||||
// Have 'dummy ares' respond immediately.
|
||||
LLAresListener dummyLLAres("dummy_llares", respond_immediately);
|
||||
dummyLLAres.listenTo(llaresPump);
|
||||
|
||||
// Have dummy XMLRPC respond immediately.
|
||||
LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc", respond_immediately);
|
||||
|
|
@ -264,111 +205,14 @@ namespace tut
|
|||
|
||||
template<> template<>
|
||||
void llviewerlogin_object::test<2>()
|
||||
{
|
||||
DEBUG;
|
||||
// Tests a successful login in with delayed responses.
|
||||
// Also includes 'failure' that cause the login module
|
||||
// to re-attempt connection, once from a basic failure
|
||||
// and once from the 'indeterminate' response.
|
||||
|
||||
set_test_name("LLLogin multiple srv uris w/ success");
|
||||
|
||||
// Testing normal login procedure.
|
||||
LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
|
||||
LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump
|
||||
|
||||
bool respond_immediately = false;
|
||||
bool multiple_addresses = true;
|
||||
LLAresListener dummyLLAres("dummy_llares", respond_immediately, multiple_addresses);
|
||||
dummyLLAres.listenTo(llaresPump);
|
||||
|
||||
LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc");
|
||||
dummyXMLRPC.listenTo(xmlrpcPump);
|
||||
|
||||
LLLogin login;
|
||||
|
||||
LoginListener listener("test_ear");
|
||||
listener.listenTo(login.getEventPump());
|
||||
|
||||
LLSD credentials;
|
||||
credentials["first"] = "foo";
|
||||
credentials["last"] = "bar";
|
||||
credentials["passwd"] = "secret";
|
||||
|
||||
login.connect("login.bar.com", credentials);
|
||||
|
||||
ensure_equals("SRV state", listener.lastEvent()["change"].asString(), "srvrequest");
|
||||
|
||||
dummyLLAres.sendReply();
|
||||
|
||||
// Test Authenticating State prior to first response.
|
||||
ensure_equals("Auth state 1", listener.lastEvent()["change"].asString(), "authenticating");
|
||||
ensure_equals("Attempt 1", listener.lastEvent()["data"]["attempt"].asInteger(), 1);
|
||||
ensure_equals("URI 1", listener.lastEvent()["data"]["request"]["uri"].asString(), "login.foo.com");
|
||||
|
||||
// First send emulated LLXMLRPCListener failure,
|
||||
// this should return login to the authenticating step and increase the attempt
|
||||
// count.
|
||||
LLSD data;
|
||||
data["status"] = "OtherError";
|
||||
data["errorcode"] = 0;
|
||||
data["error"] = "dummy response";
|
||||
data["transfer_rate"] = 0;
|
||||
dummyXMLRPC.setResponse(data);
|
||||
dummyXMLRPC.sendReply();
|
||||
|
||||
ensure_equals("Fail back to authenticate 1", listener.lastEvent()["change"].asString(), "authenticating");
|
||||
ensure_equals("Attempt 2", listener.lastEvent()["data"]["attempt"].asInteger(), 2);
|
||||
ensure_equals("URI 2", listener.lastEvent()["data"]["request"]["uri"].asString(), "login.bar.com");
|
||||
|
||||
// Now send the 'indeterminate' response.
|
||||
data.clear();
|
||||
data["status"] = "Complete"; // StatusComplete
|
||||
data["errorcode"] = 0;
|
||||
data["error"] = "dummy response";
|
||||
data["transfer_rate"] = 0;
|
||||
data["responses"]["login"] = "indeterminate";
|
||||
data["responses"]["next_url"] = "login.indeterminate.com";
|
||||
data["responses"]["next_method"] = "test_login_method";
|
||||
dummyXMLRPC.setResponse(data);
|
||||
dummyXMLRPC.sendReply();
|
||||
|
||||
ensure_equals("Fail back to authenticate 2", listener.lastEvent()["change"].asString(), "authenticating");
|
||||
ensure_equals("Attempt 3", listener.lastEvent()["data"]["attempt"].asInteger(), 3);
|
||||
ensure_equals("URI 3", listener.lastEvent()["data"]["request"]["uri"].asString(), "login.indeterminate.com");
|
||||
ensure_equals("Method 3", listener.lastEvent()["data"]["request"]["method"].asString(), "test_login_method");
|
||||
|
||||
// Finally let the auth succeed.
|
||||
data.clear();
|
||||
data["status"] = "Complete"; // StatusComplete
|
||||
data["errorcode"] = 0;
|
||||
data["error"] = "dummy response";
|
||||
data["transfer_rate"] = 0;
|
||||
data["responses"]["login"] = "true";
|
||||
dummyXMLRPC.setResponse(data);
|
||||
dummyXMLRPC.sendReply();
|
||||
|
||||
ensure_equals("Success state", listener.lastEvent()["state"].asString(), "online");
|
||||
|
||||
login.disconnect();
|
||||
|
||||
ensure_equals("Disconnected state", listener.lastEvent()["state"].asString(), "offline");
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void llviewerlogin_object::test<3>()
|
||||
{
|
||||
DEBUG;
|
||||
// Test completed response, that fails to login.
|
||||
set_test_name("LLLogin valid response, failure (eg. bad credentials)");
|
||||
|
||||
// Testing normal login procedure.
|
||||
LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
|
||||
LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump
|
||||
|
||||
LLAresListener dummyLLAres("dummy_llares");
|
||||
dummyLLAres.listenTo(llaresPump);
|
||||
|
||||
LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc");
|
||||
dummyXMLRPC.listenTo(xmlrpcPump);
|
||||
|
||||
|
|
@ -383,10 +227,6 @@ namespace tut
|
|||
|
||||
login.connect("login.bar.com", credentials);
|
||||
|
||||
ensure_equals("SRV state", listener.lastEvent()["change"].asString(), "srvrequest");
|
||||
|
||||
dummyLLAres.sendReply();
|
||||
|
||||
ensure_equals("Auth state", listener.lastEvent()["change"].asString(), "authenticating");
|
||||
|
||||
// Send the failed auth request reponse
|
||||
|
|
@ -403,19 +243,15 @@ namespace tut
|
|||
}
|
||||
|
||||
template<> template<>
|
||||
void llviewerlogin_object::test<4>()
|
||||
void llviewerlogin_object::test<3>()
|
||||
{
|
||||
DEBUG;
|
||||
// Test incomplete response, that end the attempt.
|
||||
set_test_name("LLLogin valid response, failure (eg. bad credentials)");
|
||||
|
||||
// Testing normal login procedure.
|
||||
LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
|
||||
LLEventStream xmlrpcPump("LLXMLRPCTransaction"); // Dummy XMLRPC pump
|
||||
|
||||
LLAresListener dummyLLAres("dummy_llares");
|
||||
dummyLLAres.listenTo(llaresPump);
|
||||
|
||||
LLXMLRPCListener dummyXMLRPC("dummy_xmlrpc");
|
||||
dummyXMLRPC.listenTo(xmlrpcPump);
|
||||
|
||||
|
|
@ -430,10 +266,6 @@ namespace tut
|
|||
|
||||
login.connect("login.bar.com", credentials);
|
||||
|
||||
ensure_equals("SRV state", listener.lastEvent()["change"].asString(), "srvrequest");
|
||||
|
||||
dummyLLAres.sendReply();
|
||||
|
||||
ensure_equals("Auth state", listener.lastEvent()["change"].asString(), "authenticating");
|
||||
|
||||
// Send the failed auth request reponse
|
||||
|
|
@ -449,17 +281,13 @@ namespace tut
|
|||
}
|
||||
|
||||
template<> template<>
|
||||
void llviewerlogin_object::test<5>()
|
||||
void llviewerlogin_object::test<4>()
|
||||
{
|
||||
DEBUG;
|
||||
// Test SRV request timeout.
|
||||
set_test_name("LLLogin SRV timeout testing");
|
||||
|
||||
// Testing normal login procedure.
|
||||
LLEventStream llaresPump("LLAres"); // Dummy LLAres pump.
|
||||
|
||||
LLAresListener dummyLLAres("dummy_llares");
|
||||
dummyLLAres.listenTo(llaresPump);
|
||||
|
||||
LLLogin login;
|
||||
LoginListener listener("test_ear");
|
||||
|
|
@ -473,26 +301,15 @@ namespace tut
|
|||
|
||||
login.connect("login.bar.com", credentials);
|
||||
|
||||
ensure_equals("SRV State", listener.lastEvent()["change"].asString(), "srvrequest");
|
||||
|
||||
// Get the mainloop eventpump, which needs a pinging in order to drive the
|
||||
// SRV timeout.
|
||||
LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop"));
|
||||
LLSD frame_event;
|
||||
mainloop.post(frame_event);
|
||||
|
||||
// In this state we have NOT sent a reply from LLAresListener -- in
|
||||
// fact there's no such object. Nonetheless, we expect the timeout to
|
||||
// have stepped the login module forward to try to authenticate with
|
||||
// the original URI.
|
||||
ensure_equals("Auth state", listener.lastEvent()["change"].asString(), "authenticating");
|
||||
ensure_equals("Attempt", listener.lastEvent()["data"]["attempt"].asInteger(), 1);
|
||||
ensure_equals("URI", listener.lastEvent()["data"]["request"]["uri"].asString(), "login.bar.com");
|
||||
|
||||
// EXT-4193: if the SRV reply isn't lost but merely late, and if it
|
||||
// arrives just at the moment we're expecting the XMLRPC reply, the
|
||||
// original code got confused and crashed. Drive that case here. We
|
||||
// observe that without the fix, this call DOES repro.
|
||||
dummyLLAres.sendReply();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue