📄 dnsresult.cxx
字号:
{
assert(mCurrResultPath.size()<=2);
Item top;
if (!mCurrResultPath.empty())
{
top = mCurrResultPath.top();
if (top.rrType == T_SRV)
{
vector<Data> records;
records.push_back(top.value);
mDns.blacklist(top.domain, top.rrType, Protocol::Sip, records);
mCurrResultPath.pop();
}
else
{
assert(top.rrType==T_NAPTR);
}
}
while (!mCurrSuccessPath.empty())
{
top = mCurrSuccessPath.top();
if (top.rrType != T_NAPTR)
{
mCurrSuccessPath.pop();
}
else
{
break;
}
}
top.domain = next.key;
top.rrType = T_SRV;
top.value = next.target + ":" + Data(next.port);
mCurrResultPath.push(top);
mCurrSuccessPath.push(top);
lookupHost(next.target);
}
else
{
assert(0);
if (mHandler) mHandler->handle(this);
}
// don't call primeResults since we need to wait for the response to
// AAAA/A query first
}
else
{
bool changed = (mType == Pending);
transition(Finished);
if (!mCurrResultPath.empty())
{
assert(mCurrResultPath.size()<=2);
while (!mCurrResultPath.empty())
{
Item top = mCurrResultPath.top();
vector<Data> records;
records.push_back(top.value);
mDns.blacklist(top.domain, top.rrType, Protocol::Sip, records);
mCurrResultPath.pop();
}
}
if (changed && mHandler) mHandler->handle(this);
}
// Either we are finished or there are results primed
//assert(mType == Finished || // !slg! handle() might end up destroying the DnsResult - so we can't safely do this assert
// mType == Pending ||
// (mType == Available && !mResults.empty())
// );
}
// implement the selection algorithm from rfc2782 (SRV records)
DnsResult::SRV
DnsResult::retrieveSRV()
{
// !ah! if mTransport is known -- should we ignore those that don't match?!
assert(!mSRVResults.empty());
const SRV& srv = *mSRVResults.begin();
if (srv.cumulativeWeight == 0)
{
int priority = srv.priority;
mCumulativeWeight=0;
//!dcm! -- this should be fixed properly; TCP req. lines were being sent
//out on UDP
TransportType transport = mSRVResults.begin()->transport;
for (std::vector<SRV>::iterator i=mSRVResults.begin();
i!=mSRVResults.end()
&& i->priority == priority
&& i->transport == transport; i++)
{
mCumulativeWeight += i->weight;
i->cumulativeWeight = mCumulativeWeight;
}
}
int selected = Random::getRandom() % (mCumulativeWeight+1);
StackLog (<< "cumulative weight = " << mCumulativeWeight << " selected=" << selected);
std::vector<SRV>::iterator i;
for (i=mSRVResults.begin(); i!=mSRVResults.end(); i++)
{
if (i->cumulativeWeight >= selected)
{
break;
}
}
if (i == mSRVResults.end())
{
InfoLog (<< "SRV Results problem selected=" << selected << " cum=" << mCumulativeWeight);
}
assert(i != mSRVResults.end());
SRV next = *i;
mCumulativeWeight -= next.cumulativeWeight;
mSRVResults.erase(i);
StackLog (<< "SRV: " << Inserter(mSRVResults));
return next;
}
// adapted from the adig.c example in ares
const unsigned char*
DnsResult::skipDNSQuestion(const unsigned char *aptr,
const unsigned char *abuf,
int alen)
{
char *name=0;
int status=0;
int len=0;
// Parse the question name.
status = ares_expand_name(aptr, abuf, alen, &name, &len);
if (status != ARES_SUCCESS)
{
StackLog (<< "Failed parse of RR");
return NULL;
}
aptr += len;
// Make sure there's enough data after the name for the fixed part
// of the question.
if (aptr + QFIXEDSZ > abuf + alen)
{
free(name);
StackLog (<< "Failed parse of RR");
return NULL;
}
// Parse the question type and class.
//int type = DNS_QUESTION_TYPE(aptr);
//int dnsclass = DNS_QUESTION_CLASS(aptr);
aptr += QFIXEDSZ;
free(name);
return aptr;
}
DnsResult::NAPTR::NAPTR() : order(0), pref(0)
{
}
bool
DnsResult::NAPTR::operator<(const DnsResult::NAPTR& rhs) const
{
if (key.empty()) // default value
{
return false;
}
else if (rhs.key.empty()) // default value
{
return true;
}
else if (order < rhs.order)
{
return true;
}
else if (order == rhs.order)
{
if (pref < rhs.pref)
{
return true;
}
else if (pref == rhs.pref)
{
return replacement < rhs.replacement;
}
}
return false;
}
DnsResult::SRV::SRV() : priority(0), weight(0), cumulativeWeight(0), port(0)
{
}
bool
DnsResult::SRV::operator<(const DnsResult::SRV& rhs) const
{
if (transport < rhs.transport)
{
return true;
}
else if (transport == rhs.transport)
{
if (priority < rhs.priority)
{
return true;
}
else if (priority == rhs.priority)
{
if (weight < rhs.weight)
{
return true;
}
else if (weight == rhs.weight)
{
if (target < rhs.target)
{
return true;
}
}
}
}
return false;
}
void DnsResult::onDnsResult(const DNSResult<DnsHostRecord>& result)
{
if (!mInterface.isSupported(mTransport, V4) && !mInterface.isSupported(mTransport, V6))
{
return;
}
StackLog (<< "Received dns result for: " << mTarget);
StackLog (<< "DnsResult::onDnsResult() " << result.status);
// This function assumes that the A query that caused this callback
// is the _only_ outstanding DNS query that might result in a
// callback into this function
if ( mType == Destroyed )
{
destroy();
return;
}
if (result.status == 0)
{
for (vector<DnsHostRecord>::const_iterator it = result.records.begin(); it != result.records.end(); ++it)
{
in_addr addr;
addr.s_addr = (*it).addr().s_addr;
Tuple tuple(addr, mPort, mTransport, mTarget);
StackLog (<< "Adding " << tuple << " to result set");
mResults.push_back(tuple);
}
}
else
{
StackLog (<< "Failed async A query: " << result.msg);
}
if (mSRVCount == 0)
{
bool changed = (mType == Pending);
if (mResults.empty())
{
#ifdef WIN32_SYNCRONOUS_RESOLUTION_ON_ARES_FAILURE
// Try Windows Name Resolution (not asyncronous)
WSAQUERYSET QuerySet = { 0 };
GUID guidServiceTypeUDP = SVCID_UDP(mPort);
GUID guidServiceTypeTCP = SVCID_TCP(mPort);
HANDLE hQuery;
QuerySet.dwSize = sizeof(WSAQUERYSET);
QuerySet.lpServiceClassId = mTransport == UDP ? &guidServiceTypeUDP : &guidServiceTypeTCP;
QuerySet.dwNameSpace = NS_ALL;
QuerySet.lpszServiceInstanceName = (char *)mTarget.c_str();
if(WSALookupServiceBegin(&QuerySet, LUP_RETURN_ADDR, &hQuery) == 0)
{
DWORD dwQuerySize = 256; // Starting size
int iRet = 0;
bool fDone = false;
LPWSAQUERYSET pQueryResult = (LPWSAQUERYSET) new char[dwQuerySize];
while(iRet == 0 && pQueryResult)
{
iRet = WSALookupServiceNext(hQuery, 0, &dwQuerySize, pQueryResult);
if(pQueryResult && iRet == -1 && GetLastError() == WSAEFAULT)
{
delete [] pQueryResult;
pQueryResult = (LPWSAQUERYSET) new char[dwQuerySize]; // Re-allocate new size
iRet = WSALookupServiceNext(hQuery, 0, &dwQuerySize, pQueryResult);
}
if(pQueryResult && iRet == 0)
{
for(DWORD i = 0; i < pQueryResult->dwNumberOfCsAddrs; i++)
{
SOCKADDR_IN *pSockAddrIn = (SOCKADDR_IN *)pQueryResult->lpcsaBuffer[i].RemoteAddr.lpSockaddr;
Tuple tuple(pSockAddrIn->sin_addr, mPort, mTransport, mTarget);
StackLog (<< "Adding (WIN) " << tuple << " to result set");
mResults.push_back(tuple);
mType = Available;
}
}
}
delete [] pQueryResult;
WSALookupServiceEnd(hQuery);
}
if(mResults.empty())
{
mType = Finished;
}
#else
mType = Finished;
#endif
clearCurrPath();
}
else
{
if (mSRVResults.empty())
{
transition(Available);
}
else
{
mType = Available;
}
addToPath(mResults);
}
if (changed && mHandler) mHandler->handle(this);
}
}
#ifdef USE_IPV6
void DnsResult::onDnsResult(const DNSResult<DnsAAAARecord>& result)
{
StackLog (<< "Received AAAA result for: " << mTarget);
if (!mInterface.isSupported(mTransport, V6))
{
return;
}
StackLog (<< "DnsResult::onDnsResult() " << result.status);
assert(mInterface.isSupported(mTransport, V6));
// This function assumes that the AAAA query that caused this callback
// is the _only_ outstanding DNS query that might result in a
// callback into this function
if ( mType == Destroyed )
{
destroy();
return;
}
if (result.status == 0)
{
for (vector<DnsAAAARecord>::const_iterator it = result.records.begin(); it != result.records.end(); ++it)
{
Tuple tuple((*it).v6Address(), mPort, mTransport, mTarget);
StackLog (<< "Adding " << tuple << " to result set");
mResults.push_back(tuple);
}
}
else
{
StackLog (<< "Failed async AAAA query: " << result.msg);
}
// funnel through to host processing
mDns.lookup<RR_A>(mPassHostFromAAAAtoA, Protocol::Sip, this);
}
#endif
void DnsResult::onDnsResult(const DNSResult<DnsSrvRecord>& result)
{
StackLog (<< "Received SRV result for: " << mTarget);
assert(mSRVCount>=0);
mSRVCount--;
StackLog (<< "DnsResult::onDnsResult() " << mSRVCount << " status=" << result.status);
// There could be multiple SRV queries outstanding, but there will be no
// other DNS queries outstanding that might cause a callback into this
// object.
if (mType == Destroyed && mSRVCount == 0)
{
destroy();
return;
}
if (result.status == 0)
{
for (vector<DnsSrvRecord>::const_iterator it = result.records.begin(); it != result.records.end(); ++it)
{
SRV srv;
srv.key = (*it).name();
srv.priority = (*it).priority();
srv.weight = (*it).weight();
srv.port = (*it).port();
srv.target = (*it).target();
if (srv.key.find("_sips._udp") != Data::npos)
{
srv.transport = DTLS;
}
else if (srv.key.find("_sips._tcp") != Data::npos)
{
srv.transport = TLS;
}
else if (srv.key.find("_udp") != Data::npos)
{
srv.transport = UDP;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -