Added Resolver class to engine. Use it in jabber library.

git-svn-id: http://voip.null.ro/svn/yate@4548 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
marian 2011-08-19 13:04:53 +00:00
parent a2b2595631
commit b6355eecd6
7 changed files with 848 additions and 193 deletions

View File

@ -24,7 +24,7 @@ EINC := $(CINC) @top_srcdir@/yatengine.h
PINC := $(EINC) @top_srcdir@/yatephone.h
CLINC:= $(PINC) @top_srcdir@/yatecbase.h
LIBS :=
CLSOBJS := TelEngine.o ObjList.o HashList.o Mutex.o Thread.o Socket.o \
CLSOBJS := TelEngine.o ObjList.o HashList.o Mutex.o Thread.o Socket.o Resolver.o \
String.o DataBlock.o NamedList.o Evaluator.o \
URI.o Mime.o Array.o Iterator.o \
YMD5.o YSHA1.o Base64.o Cipher.o Compressor.o
@ -91,6 +91,9 @@ DataFormat.o: @srcdir@/DataFormat.cpp $(MKDEPS) $(PINC)
Socket.o: @srcdir@/Socket.cpp $(MKDEPS) $(CINC)
$(COMPILE) @FDSIZE_HACK@ @NETDB_FLAGS@ -c $<
Resolver.o: @srcdir@/Resolver.cpp $(MKDEPS) $(CINC)
$(COMPILE) @RESOLV_INC@ -c $<
Mutex.o: @srcdir@/Mutex.cpp $(MKDEPS) $(CINC)
$(COMPILE) @MUTEX_HACK@ -c $<
@ -116,4 +119,4 @@ Makefile: @srcdir@/Makefile.in $(MKDEPS)
cd .. && ./config.status
../$(YLIB): $(LIBOBJS) $(LIBS)
$(LINK) -o $@ $(SONAME_OPT)$(YLIB) $^ $(LIBTHR) $(LIBAUX)
$(LINK) -o $@ $(SONAME_OPT)$(YLIB) $^ $(LIBTHR) $(LIBAUX) @RESOLV_LIB@

588
engine/Resolver.cpp Normal file
View File

@ -0,0 +1,588 @@
/**
* Resolver.cpp
* This file is part of the YATE Project http://YATE.null.ro
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2011 Null Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
Preprocessor definitions:
WINDOWS:
HAVE_DNS_NAPTR_DATA: Define it if DNS_NAPTR_DATA is defined in windns.h
If defined, NAPTR query will work at runtime on all supported versions
If not defined NAPTR query will work only if Windows major version is less then 6
Non Windows
NO_RESOLV: Defined if the resolver is not available at compile time
NO_DN_SKIPNAME: Define it if __dn_skipname() is not available at link time
*/
#include "yateclass.h"
#ifdef _WINDOWS
#include <windns.h>
#elif !defined(NO_RESOLV)
#include <resolv.h>
#include <arpa/nameser.h>
#endif // _WINDOWS
using namespace TelEngine;
// Resolver type names
const TokenDict Resolver::s_types[] = {
{ "SRV", Srv },
{ "NAPTR", Naptr },
{ 0, 0 },
};
#ifdef _WINDOWS
class WindowsVersion
{
public:
WindowsVersion();
inline unsigned int major() const
{ return m_major; }
private:
unsigned int m_major;
};
WindowsVersion::WindowsVersion()
: m_major(0)
{
OSVERSIONINFOA ver;
::ZeroMemory(&ver,sizeof(OSVERSIONINFOA));
ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (::GetVersionEx(&ver))
m_major = ver.dwMajorVersion;
if (!m_major)
Debug(DebugWarn,"Resolver failed to detect Windows version");
}
static WindowsVersion s_winVer;
#endif
// Utility: print the result of dns query
// Return the code
static int printResult(int type, int code, const char* dname, ObjList& result, String* error)
{
#ifdef DEBUG
if (!code) {
String s;
int crt = 0;
for (ObjList* o = result.skipNull(); o; o = o->skipNext()) {
DnsRecord* rec = static_cast<DnsRecord*>(o->get());
if (!s)
s << "\r\n-----";
s << "\r\n" << ++crt << ":";
rec->dump(s);
}
if (s)
s << "\r\n-----";
Debug(DebugAll,"%s query for '%s' got %d records%s",
lookup(type,Resolver::s_types),dname,result.count(),s.safe());
}
else {
String dummy;
if (!error) {
error = &dummy;
#ifdef _WINDOWS
Thread::errorString(dummy,code);
#elif defined(__NAMESER)
dummy = hstrerror(code);
#endif
}
Debug(DebugNote,"%s query for '%s' failed with code %d error=%s",
lookup(type,Resolver::s_types),dname,code,TelEngine::c_safe(error));
}
#endif
return code;
}
// Utility: print a record and insert it in list
static bool insertRecord(ObjList& result, DnsRecord* rec, bool ascPref, const char* str)
{
#ifdef XDEBUG
if (rec) {
String s;
rec->dump(s);
Debug(DebugAll,"%s inserting %s",str,s.c_str());
}
#endif
return DnsRecord::insert(result,rec,ascPref);
}
/*
* __dn_skipname() not available at link time
*/
#ifdef NO_DN_SKIPNAME
#define RESOLVER_NAME_COMPRESSED 0xc0 // Name compressed mask
#define RESOLVER_NAME_COMPRESSED_EXT 0x40 // RFC 2671 extended label type
#define RESOLVER_NAME_COMPRESSED_EXT_NEXT 0x41 // RFC 2671 extended label type with length in the next byte
#ifndef dn_skipname
#define dn_skipname __dn_skipname
#endif
// Retrieve the length of an extended compressed or uncompressed name
static int dn_namelen_ext(const unsigned char* buf)
{
if (!buf)
return -1;
unsigned char val = *buf;
unsigned char comp = (val & RESOLVER_NAME_COMPRESSED);
// Compressed but not using extension: error
if (comp == RESOLVER_NAME_COMPRESSED)
return -1;
// Not using extended compression
if (comp != RESOLVER_NAME_COMPRESSED_EXT)
return val;
// Extended compression with length in the next byte
if (val == RESOLVER_NAME_COMPRESSED_EXT_NEXT) {
int nBits = buf[1];
if (!nBits)
nBits = 256;
return (nBits + 7) / 8 + 1;
}
DDebug(DebugNote,"dn_namelen_ext(%p) unknown extended compression %xd",buf,val);
return -1;
}
extern "C" int __dn_skipname(const unsigned char* start, const unsigned char* end)
{
XDebug(DebugNote,"__dn_skipname(%p,%p)",start,end);
const unsigned char* buf = start;
bool ok = true;
while (buf < end) {
unsigned char c = *buf++;
if (!c)
break;
unsigned char comp = (c & RESOLVER_NAME_COMPRESSED);
// Not compressed
if (!comp) {
buf += c;
continue;
}
// Compressed
if (comp == RESOLVER_NAME_COMPRESSED) {
buf++;
break;
}
// Extended compression
if (comp == RESOLVER_NAME_COMPRESSED_EXT) {
int len = dn_namelen_ext(buf - 1);
if (len >= 0) {
buf += len;
continue;
}
ok = false;
break;
}
DDebug(DebugNote,"__dn_skipname: unknown compression type %xd",comp);
// Unknown compression
ok = false;
break;
}
if (!ok || buf > end) {
h_errno = EMSGSIZE;
return -1;
}
return buf - start;
}
#endif // NO_DN_SKIPNAME
// weird but NS_MAXSTRING and dn_string() are NOT part of the resolver API...
#ifndef NS_MAXSTRING
#define NS_MAXSTRING 255
#endif
// copy one string (not domain) from response
static int dn_string(const unsigned char* end, const unsigned char* src, char* dest, int maxlen)
{
if (!src)
return 0;
int n = src[0];
if (!dest)
return n + 1;
maxlen--;
if (maxlen > n)
maxlen = n;
while ((maxlen-- > 0) && (src < end))
*dest++ = *++src;
*dest = 0;
return n + 1;
}
// Dump a record for debug purposes
void DnsRecord::dump(String& buf, const char* sep)
{
buf.append("order=",sep) << m_order;
buf << sep << "pref=" << m_pref;
}
// Insert a record into a list in the proper location
// Order records ascending by their order
// Look at ascPref for records with the same order
bool DnsRecord::insert(ObjList& list, DnsRecord* rec, bool ascPref)
{
if (!rec || list.find(rec))
return false;
XDebug(DebugAll,"DnsRecord::insert(%p) order=%d pref=%d",rec,rec->order(),rec->pref());
ObjList* o = list.skipNull();
for (; o; o = o->skipNext()) {
DnsRecord* crt = static_cast<DnsRecord*>(o->get());
if (rec->order() > crt->order())
continue;
if (rec->order() == crt->order()) {
for (; o; o = o->skipNext()) {
DnsRecord* crt = static_cast<DnsRecord*>(o->get());
if (crt->order() != rec->order())
break;
if (crt->pref() == rec->pref())
continue;
if (ascPref == (rec->pref() < crt->pref()))
break;
}
}
break;
}
if (o)
o->insert(rec);
else
list.append(rec);
return true;
}
// Dump a record for debug purposes
void SrvRecord::dump(String& buf, const char* sep)
{
DnsRecord::dump(buf,sep);
buf.append("address=",sep) << "'" << m_address << "'";
buf << sep << "port=" << m_port;
}
// Copy a SrvRecord list into another one
void SrvRecord::copy(ObjList& dest, const ObjList& src)
{
dest.clear();
for (ObjList* o = src.skipNull(); o; o = o->skipNext()) {
SrvRecord* rec = static_cast<SrvRecord*>(o->get());
dest.append(new SrvRecord(rec->order(),rec->pref(),rec->address(),rec->port()));
}
}
NaptrRecord::NaptrRecord(int ord, int pref, const char* flags, const char* serv,
const char* regexp, const char* next)
: DnsRecord(ord,pref),
m_flags(flags), m_service(serv), m_next(next)
{
// use case-sensitive extended regular expressions
m_regmatch.setFlags(true,false);
if (!null(regexp)) {
// look for <sep>regexp<sep>template<sep>
char sep[2] = { regexp[0], 0 };
String tmp(regexp+1);
if (tmp.endsWith(sep)) {
int pos = tmp.find(sep);
if (pos > 0) {
m_regmatch = tmp.substr(0,pos);
m_template = tmp.substr(pos+1,tmp.length()-pos-2);
XDebug(DebugAll,"NaptrRecord match '%s' template '%s'",
m_regmatch.c_str(),m_template.c_str());
}
}
}
}
// Perform the Regexp replacement, return true if succeeded
bool NaptrRecord::replace(String& str)
{
if (m_regmatch && str.matches(m_regmatch)) {
str = str.replaceMatches(m_template);
return true;
}
return false;
}
// Dump a record for debug purposes
void NaptrRecord::dump(String& buf, const char* sep)
{
DnsRecord::dump(buf,sep);
buf.append("flags=",sep) << "'" << m_flags << "'";
buf << sep << "service=" << "'" << m_service << "'";
buf << sep << "regmatch=" << "'" << m_regmatch << "'";
buf << sep << "template=" << "'" << m_template << "'";
buf << sep << "next=" << "'" << m_next << "'";
}
// Runtime check for resolver availability
bool Resolver::available(Type t)
{
#ifdef _WINDOWS
if (t == Naptr) {
if (!s_winVer.major())
return false;
#ifdef HAVE_DNS_NAPTR_DATA
return true;
#else
return s_winVer.major() < 6;
#endif
}
return true;
#elif defined(__NAMESER)
return true;
#endif
return false;
}
// Initialize the resolver in the current thread
bool Resolver::init(int timeout, int retries)
{
if (!available())
return false;
#ifdef _WINDOWS
return true;
#elif defined(__NAMESER)
if ((_res.options & RES_INIT) == 0) {
// need to initialize in current thread
if (res_init())
return false;
}
// always set variables
if (timeout >= 0)
_res.retrans = timeout;
if (retries >= 0)
_res.retry = retries;
return true;
#endif
return false;
}
// Make a query
int Resolver::query(Type type, const char* dname, ObjList& result, String* error)
{
if (type == Srv)
return srvQuery(dname,result,error);
if (type == Naptr)
return naptrQuery(dname,result,error);
Debug(DebugStub,"Resolver query not implemented for type %d",type);
return 0;
}
// Make a SRV query
int Resolver::srvQuery(const char* dname, ObjList& result, String* error)
{
int code = 0;
XDebug(DebugAll,"Starting %s query for '%s'",lookup(Srv,s_types),dname);
#ifdef _WINDOWS
DNS_RECORD* srv = 0;
code = (int)::DnsQuery_UTF8(dname,DNS_TYPE_SRV,DNS_QUERY_STANDARD,NULL,&srv,NULL);
if (code == ERROR_SUCCESS) {
for (DNS_RECORD* dr = srv; dr; dr = dr->pNext) {
if (dr->wType != DNS_TYPE_SRV || dr->wDataLength != sizeof(DNS_SRV_DATA))
continue;
DNS_SRV_DATA& d = dr->Data.SRV;
insertRecord(result,new SrvRecord(d.wPriority,d.wWeight,
d.pNameTarget,d.wPort),false,"srvQuery");
}
}
else if (error)
Thread::errorString(*error,code);
if (srv)
::DnsRecordListFree(srv,DnsFreeRecordList);
#elif defined(__NAMESER)
unsigned char buf[512];
int r = res_query(dname,ns_c_in,ns_t_srv,buf,sizeof(buf));
if (r <= 0 || r > (int)sizeof(buf)) {
if (r) {
code = h_errno;
if (error)
*error = hstrerror(code);
}
return printResult(Srv,code,dname,result,error);
}
int queryCount = 0;
int answerCount = 0;
unsigned char* p = buf + NS_QFIXEDSZ;
unsigned char* e = buf + r;
NS_GET16(queryCount,p);
NS_GET16(answerCount,p);
p = buf + NS_HFIXEDSZ;
// Skip queries
for (; queryCount > 0; queryCount--) {
int n = dn_skipname(p,e);
if (n < 0)
break;
p += (n + NS_QFIXEDSZ);
}
for (int i = 0; i < answerCount; i++) {
char name[NS_MAXLABEL + 1];
// Skip this answer's query
int n = dn_expand(buf,e,p,name,sizeof(name));
if ((n <= 0) || (n > NS_MAXLABEL))
break;
buf[n] = 0;
p += n;
// Get record type, class, ttl, length
int rrType, rrClass, rrTtl, rrLen;
NS_GET16(rrType,p);
NS_GET16(rrClass,p);
NS_GET32(rrTtl,p);
NS_GET16(rrLen,p);
// Remember current pointer and skip to next answer
unsigned char* l = p;
p += rrLen;
// Skip non SRV answers
if (rrType != (int)ns_t_srv)
continue;
// Now get record priority, weight, port, label
int prio, weight, port;
NS_GET16(prio,l);
NS_GET16(weight,l);
NS_GET16(port,l);
n = dn_expand(buf,e,l,name,sizeof(name));
if ((n <= 0) || (n > NS_MAXLABEL))
break;
insertRecord(result,new SrvRecord(prio,weight,name,port),false,"srvQuery");
}
#endif
return printResult(Srv,code,dname,result,error);
}
// Make a NAPTR query
int Resolver::naptrQuery(const char* dname, ObjList& result, String* error)
{
int code = 0;
XDebug(DebugAll,"Starting %s query for '%s'",lookup(Naptr,s_types),dname);
#ifdef _WINDOWS
DNS_RECORD* naptr = 0;
if (available(Naptr))
code = (int)::DnsQuery_UTF8(dname,DNS_TYPE_NAPTR,DNS_QUERY_STANDARD,NULL,&naptr,NULL);
if (code == ERROR_SUCCESS) {
for (DNS_RECORD* dr = naptr; dr; dr = dr->pNext) {
if (dr->wType != DNS_TYPE_NAPTR)
continue;
// version >= 6: DnsQuery will set the fields in DNS_NAPTR_DATA
// else: DnsQuery puts the raw response
if (s_winVer.major() >= 6) {
#ifdef HAVE_DNS_NAPTR_DATA
if (dr->wDataLength != sizeof(DNS_NAPTR_DATA))
continue;
DNS_NAPTR_DATA& d = dr->Data.NAPTR;
insertRecord(result,new NaptrRecord(d.wOrder,d.wPreference,d.pFlags,
d.pService,d.pRegularExpression,d.pReplacement),true,"naptrQuery");
#endif
continue;
}
int len = dr->wDataLength - 4;
if (len <= 0)
continue;
unsigned char* b = (unsigned char*)&dr->Data;
int ord = (b[0] << 8) | b[1];
int pr = (b[2] << 8) | b[3];
unsigned char* tmp = new unsigned char[len + 1];
::memcpy(tmp,b + 4,len);
tmp[len] = 0;
unsigned char* buf = tmp;
unsigned char* end = buf + len;
if (!buf)
continue;
char fla[DNS_MAX_NAME_BUFFER_LENGTH];
char ser[DNS_MAX_NAME_BUFFER_LENGTH];
char reg[DNS_MAX_NAME_BUFFER_LENGTH];
buf += dn_string(end,buf,fla,sizeof(fla));;
buf += dn_string(end,buf,ser,sizeof(ser));
buf += dn_string(end,buf,reg,sizeof(reg));
insertRecord(result,new NaptrRecord(ord,pr,fla,ser,reg,0),true,"naptrQuery");
}
}
else if (error)
Thread::errorString(*error,code);
if (naptr)
::DnsRecordListFree(naptr,DnsFreeRecordList);
#elif defined(__NAMESER)
unsigned char buf[2048];
int r,q,a;
unsigned char *p, *e;
r = res_query(dname,ns_c_in,ns_t_naptr,buf,sizeof(buf));
if ((r < 0) || (r > (int)sizeof(buf))) {
code = h_errno;
if (error)
*error = hstrerror(code);
return printResult(Naptr,code,dname,result,error);
}
p = buf+NS_QFIXEDSZ;
NS_GET16(q,p);
NS_GET16(a,p);
XDebug(DebugAll,"Resolver::naptrQuery(%s) questions: %d, answers: %d",dname,q,a);
p = buf + NS_HFIXEDSZ;
e = buf + r;
for (; q > 0; q--) {
int n = dn_skipname(p,e);
if (n < 0)
return printResult(Naptr,code,dname,result,error);
p += (n + NS_QFIXEDSZ);
}
XDebug(DebugAll,"Resolver::naptrQuery(%s) skipped questions",dname);
for (; a > 0; a--) {
int ty,cl,sz;
long int tt;
char name[NS_MAXLABEL+1];
unsigned char* l;
int n = dn_expand(buf,e,p,name,sizeof(name));
if ((n <= 0) || (n > NS_MAXLABEL))
break;
buf[n] = 0;
p += n;
NS_GET16(ty,p);
NS_GET16(cl,p);
NS_GET32(tt,p);
NS_GET16(sz,p);
XDebug(DebugAll,"Resolver::naptrQuery(%s) found '%s' type %d size %d",dname,name,ty,sz);
l = p;
p += sz;
if (ty != ns_t_naptr)
continue;
int ord,pr;
char fla[NS_MAXSTRING+1];
char ser[NS_MAXSTRING+1];
char reg[NS_MAXSTRING+1];
char rep[NS_MAXLABEL+1];
NS_GET16(ord,l);
NS_GET16(pr,l);
n = dn_string(e,l,fla,sizeof(fla));
l += n;
n = dn_string(e,l,ser,sizeof(ser));
l += n;
n = dn_string(e,l,reg,sizeof(reg));
l += n;
n = dn_expand(buf,e,l,rep,sizeof(rep));
l += n;
insertRecord(result,new NaptrRecord(ord,pr,fla,ser,reg,rep),true,"naptrQuery");
}
#endif
return printResult(Naptr,code,dname,result,error);
}
/* vi: set ts=8 sw=4 sts=4 noet: */

View File

@ -59,7 +59,7 @@ Makefile: @srcdir@/Makefile.in ../../config.status
cd ../.. && ./config.status
../../$(LIBD_VER): $(OBJS) $(YXML)
$(LINK) -o $@ $(SONAME_OPT)$(LIBD_VER) $^ $(YATELIBS) @RESOLV_LIB@
$(LINK) -o $@ $(SONAME_OPT)$(LIBD_VER) $^ $(YATELIBS)
../../$(LIBD_DEV): ../../$(LIBD_VER)
cd ../.. && ln -sf $(LIBD_VER) $(LIBD_DEV)

View File

@ -635,7 +635,9 @@ void JBConnect::connect()
// Start connecting timeout
if (!notifyConnecting(true,true))
return;
int code = Resolver::srvQuery(query,m_srvs,&error);
int code = 0;
if (Resolver::init())
code = Resolver::srvQuery(query,m_srvs,&error);
// Stop the timeout if not exiting
if (exiting(sock) || !notifyConnecting(false,true)) {
terminated(0,false);
@ -654,7 +656,7 @@ void JBConnect::connect()
ObjList* o = 0;
while (0 != (o = m_srvs.skipNull())) {
SrvRecord* rec = static_cast<SrvRecord*>(o->get());
sock = connect(*rec,rec->m_port,stop);
sock = connect(rec->address(),rec->port(),stop);
o->remove();
if (sock || stop || exiting(sock)) {
terminated(sock,false);

View File

@ -27,149 +27,6 @@
using namespace TelEngine;
#ifdef _WINDOWS
#include <windns.h>
#else
#include <resolv.h>
#include <arpa/nameser.h>
#endif
// Insert a SrvRecord into a list in the proper location
void SrvRecord::insert(ObjList& list, SrvRecord* rec)
{
XDebug(DebugAll,"SrvRecord::insert(%s port=%d prio=%d weight=%d) [%p]",
rec->c_str(),rec->m_port,rec->m_priority,rec->m_weight,rec);
// NOTE: SRV records with the same priority can be returned by the query
// Their relative order is given by the weight value
// Lower priority number means a higher priority
// Higher weight number means a higher priority
// Append items with equal priority and weight in the order they arrive
for (ObjList* o = list.skipNull(); o; o = o->skipNext()) {
SrvRecord* crt = static_cast<SrvRecord*>(o->get());
// Skip lower priority values
if (rec->m_priority > crt->m_priority)
continue;
if (rec->m_priority < crt->m_priority)
o->insert(rec);
else {
// Equal priority: skip until less weight or different priority
for (; o; o = o->skipNext()) {
SrvRecord* crt = static_cast<SrvRecord*>(o->get());
if (crt->m_priority != rec->m_priority || crt->m_weight < rec->m_weight)
break;
}
if (o)
o->insert(rec);
else
list.append(rec);
}
return;
}
list.append(rec);
}
// Copy a SrvRecord list into another one
void SrvRecord::copy(ObjList& dest, const ObjList& src)
{
dest.clear();
for (ObjList* o = src.skipNull(); o; o = o->skipNext()) {
SrvRecord* rec = static_cast<SrvRecord*>(o->get());
dest.append(new SrvRecord(*rec,rec->m_port,rec->m_priority,rec->m_weight));
}
}
// Make a SRV query
int Resolver::srvQuery(const char* query, ObjList& result, String* error)
{
int code = 0;
XDebug(DebugAll,"Starting SRV query for '%s'",query);
#ifdef _WINDOWS
DNS_RECORD* srv = 0;
code = (int)::DnsQuery_UTF8(query,DNS_TYPE_SRV,DNS_QUERY_STANDARD,NULL,&srv,NULL);
if (code == ERROR_SUCCESS) {
for (DNS_RECORD* dr = srv; dr; dr = dr->pNext) {
if (dr->wType != DNS_TYPE_SRV || dr->wDataLength != sizeof(DNS_SRV_DATA))
continue;
SrvRecord::insert(result,new SrvRecord(dr->Data.SRV.pNameTarget,dr->Data.SRV.wPort,
dr->Data.SRV.wPriority,dr->Data.SRV.wWeight));
}
}
else if (error)
Thread::errorString(*error,code);
if (srv)
::DnsRecordListFree(srv,DnsFreeRecordList);
#elif defined(__NAMESER)
unsigned char buf[512];
int r = res_query(query,ns_c_in,ns_t_srv,buf,sizeof(buf));
if (r < 0) {
code = h_errno;
if (error)
*error = hstrerror(code);
}
if (!code && r > 0 && r <= (int)sizeof(buf)) {
int queryCount = 0;
int answerCount = 0;
unsigned char* p = buf + NS_QFIXEDSZ;
unsigned char* e = buf + r;
NS_GET16(queryCount,p);
NS_GET16(answerCount,p);
p = buf + NS_HFIXEDSZ;
// Skip queries
for (; queryCount > 0; queryCount--) {
int n = dn_skipname(p,e);
if (n < 0)
break;
p += (n + NS_QFIXEDSZ);
}
for (int i = 0; i < answerCount; i++) {
char name[NS_MAXLABEL + 1];
// Skip this answer's query
int n = dn_expand(buf,e,p,name,sizeof(name));
if ((n <= 0) || (n > NS_MAXLABEL))
break;
buf[n] = 0;
p += n;
// Get record type, class, ttl, length
int rrType, rrClass, rrTtl, rrLen;
NS_GET16(rrType,p);
NS_GET16(rrClass,p);
NS_GET32(rrTtl,p);
NS_GET16(rrLen,p);
// Remember current pointer and skip to next answer
unsigned char* l = p;
p += rrLen;
// Skip non SRV answers
if (rrType != (int)ns_t_srv)
continue;
// Now get record priority, weight, port, label
int prio, weight, port;
NS_GET16(prio,l);
NS_GET16(weight,l);
NS_GET16(port,l);
n = dn_expand(buf,e,l,name,sizeof(name));
if ((n <= 0) || (n > NS_MAXLABEL))
break;
SrvRecord::insert(result,new SrvRecord(name,port,prio,weight));
}
}
#endif
#ifdef XDEBUG
if (!code) {
String s;
for (ObjList* o = result.skipNull(); o; o = o->skipNext()) {
SrvRecord* rec = static_cast<SrvRecord*>(o->get());
s << " " << *rec;
s << " (prio=" << rec->m_priority << " port=" << rec->m_port;
s << " weight=" << rec->m_weight << ")";
}
Debug(DebugAll,"SRV query for '%s' got %d records%s",query,result.count(),s.safe());
}
else
Debug(DebugNote,"SRV query for '%s' failed with code %d",query,code);
#endif
return code;
}
static const JabberID s_emptyJid;
static String s_auth[] = {"password", "auth", ""};

View File

@ -66,51 +66,6 @@ class XMPPUtils; // Utilities
class XMPPDirVal; // Direction flags
class XmlElementOut; // An outgoing xml element
/**
* This class holds a SRV record returned by a query
* The String holds the domain/ip
* @short A SRV record
*/
class YJABBER_API SrvRecord : public String
{
public:
inline SrvRecord(const char* name, int port, int prio, int weight)
: String(name), m_port(port), m_priority(prio), m_weight(weight)
{}
/**
* Insert a SrvRecord into a list in the proper location
* @param list Destination list
* @param rec The item to insert
*/
static void insert(ObjList& list, SrvRecord* rec);
/**
* Copy a SrvRecord list into another one
* @param dest Destination list
* @param src Source list
*/
static void copy(ObjList& dest, const ObjList& src);
int m_port;
int m_priority;
int m_weight;
};
class YJABBER_API Resolver
{
public:
/**
* Make a SRV query
* @param query The query content
* @param result List of resulting SrvRecord items
* @param error Optional string to be filled with error string
* @return 0 on success, error code otherwise (h_errno value on Linux)
*/
static int srvQuery(const char* query, ObjList& result, String* error = 0);
};
/**
* Implements a String array set from an already allocated
* @short A String array

View File

@ -6359,6 +6359,256 @@ public:
virtual bool setPayload(u_int32_t payload) = 0;
};
/**
* This class holds a DNS (resolver) record
* @short A DNS record
*/
class YATE_API DnsRecord : public GenObject
{
YCLASS(DnsRecord,GenObject)
YNOCOPY(DnsRecord);
public:
/**
* Build a DNS record
* @param order Record order (priority)
* @param pref Record preference
*/
inline DnsRecord(int order, int pref)
: m_order(order), m_pref(pref)
{}
/**
* Default constructor
*/
inline DnsRecord()
: m_order(0), m_pref(0)
{}
/**
* Retrieve the record order
* @return Record order
*/
inline int order() const
{ return m_order; }
/**
* Retrieve the record preference
* @return Record preference
*/
inline int pref() const
{ return m_pref; }
/**
* Dump a record for debug purposes
* @param buf Destination buffer
* @param sep Fields separator
*/
virtual void dump(String& buf, const char* sep = " ");
/**
* Insert a DnsRecord into a list in the proper location given by order and preference
* @param list Destination list
* @param rec The item to insert
* @param ascPref Order preference ascending
* @return True on success, false on failure (already in the list)
*/
static bool insert(ObjList& list, DnsRecord* rec, bool ascPref);
protected:
int m_order;
int m_pref;
};
/**
* This class holds a SRV (Service Location) record
* @short A SRV record
*/
class YATE_API SrvRecord : public DnsRecord
{
YCLASS(SrvRecord,DnsRecord)
YNOCOPY(SrvRecord);
public:
/**
* Build a SRV record
* @param prio Record priority (order)
* @param weight Record weight (preference)
* @param addr Record address
* @param port Record port
*/
inline SrvRecord(int prio, int weight, const char* addr, int port)
: DnsRecord(prio,weight), m_address(addr), m_port(port)
{}
/**
* Retrieve the record address
* @return Record address
*/
inline const String& address() const
{ return m_address; }
/**
* Retrieve the record port
* @return Record port
*/
inline int port() const
{ return m_port; }
/**
* Dump this record for debug purposes
* @param buf Destination buffer
* @param sep Fields separator
*/
virtual void dump(String& buf, const char* sep = " ");
/**
* Copy a SrvRecord list into another one
* @param dest Destination list
* @param src Source list
*/
static void copy(ObjList& dest, const ObjList& src);
protected:
String m_address;
int m_port;
private:
SrvRecord() {} // No default contructor
};
/**
* This class holds a NAPTR (Naming Authority Pointer) record
* @short A NAPTR record
*/
class YATE_API NaptrRecord : public DnsRecord
{
YCLASS(NaptrRecord,DnsRecord)
YNOCOPY(NaptrRecord);
public:
/**
* Build a NAPTR record
* @param ord Record order
* @param pref Record preference
* @param flags Interpretation flags
* @param serv Available services
* @param regexp Substitution expression
* @param next Next name to query
*/
NaptrRecord(int ord, int pref, const char* flags, const char* serv,
const char* regexp, const char* next);
/**
* Replace the enclosed template in a given string if matching
* the substitution expression
* @param str String to replace
* @return True on success
*/
bool replace(String& str);
/**
* Dump this record for debug purposes
* @param buf Destination buffer
* @param sep Fields separator
*/
virtual void dump(String& buf, const char* sep = " ");
/**
* Retrieve record interpretation flags
* @return Record interpretation flags
*/
inline const String& flags() const
{ return m_flags; }
/**
* Retrieve available services
* @return Available services
*/
inline const String& serv() const
{ return m_service; }
/**
* Retrieve the next domain name to query
* @return The next domain to query
*/
inline const String& nextName() const
{ return m_next; }
protected:
String m_flags;
String m_service;
Regexp m_regmatch;
String m_template;
String m_next;
private:
NaptrRecord() {} // No default contructor
};
/**
* This class offers DNS query services
* @short DNS services
*/
class YATE_API Resolver
{
public:
/**
* Resolver handled types
*/
enum Type {
Unknown,
Srv, // SRV (Service Location)
Naptr, // NAPTR (Naming Authority Pointer)
};
/**
* Runtime check for resolver availability
* @param type Optional type to check. Set it to Unknown (default) to check
* general resolver availability
* @return True if the resolver is available on current platform
*/
static bool available(Type type = Unknown);
/**
* Initialize the resolver in the current thread
* @param timeout Query timeout. Negative to use default
* @param retries The number of query retries. Negative to use default
* @return True on success
*/
static bool init(int timeout = -1, int retries = -1);
/**
* Make a query
* @param type Query type as enumeration
* @param dname Domain to query
* @param result List of resulting record items
* @param error Optional string to be filled with error string
* @return 0 on success, error code otherwise (h_errno value on Linux)
*/
static int query(Type type, const char* dname, ObjList& result, String* error = 0);
/**
* Make a SRV (Service Location) query
* @param dname Domain to query
* @param result List of resulting SrvRecord items
* @param error Optional string to be filled with error string
* @return 0 on success, error code otherwise (h_errno value on Linux)
*/
static int srvQuery(const char* dname, ObjList& result, String* error = 0);
/**
* Make a NAPTR (Naming Authority Pointer) query
* @param dname Domain to query
* @param result List of resulting NaptrRecord items
* @param error Optional string to be filled with error string
* @return 0 on success, error code otherwise (h_errno value on Linux)
*/
static int naptrQuery(const char* dname, ObjList& result, String* error = 0);
/**
* Resolver type names
*/
static const TokenDict s_types[];
};
/**
* The Cipher class provides an abstraction for data encryption classes
* @short An abstract cipher