21 # include <sys/types.h>
27 #if ( !defined( _WIN32 ) && !defined( _WIN32_WCE ) ) || defined( __SYMBIAN32__ )
28 # include <netinet/in.h>
29 # include <arpa/nameser.h>
32 # include <arpa/inet.h>
33 # include <sys/socket.h>
39 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
40 # include <winsock2.h>
41 # include <ws2tcpip.h>
42 #elif defined( _WIN32_WCE )
43 # include <winsock2.h>
50 #define SRV_COST (RRFIXEDSZ+0)
51 #define SRV_WEIGHT (RRFIXEDSZ+2)
52 #define SRV_PORT (RRFIXEDSZ+4)
53 #define SRV_SERVER (RRFIXEDSZ+6)
54 #define SRV_FIXEDSZ (RRFIXEDSZ+6)
62 # define DNS_TYPE_SRV 33
66 # define NS_CMPRSFLGS 0xc0
73 #ifndef INVALID_SOCKET
74 # define INVALID_SOCKET -1
77 #define XMPP_PORT 5222
82 #if defined( HAVE_RES_QUERYDOMAIN ) && defined( HAVE_DN_SKIPNAME ) && defined( HAVE_RES_QUERY )
84 const std::string& domain,
const LogSink& logInstance )
89 const std::string dname =
"_" + service +
"._" + proto;
92 srvbuf.len = res_querydomain( dname.c_str(),
const_cast<char*
>( domain.c_str() ),
93 C_IN, T_SRV, srvbuf.buf, NS_PACKETSZ );
95 srvbuf.len = res_query( dname.c_str(), C_IN, T_SRV, srvbuf.buf, NS_PACKETSZ );
98 return defaultHostMap( domain, logInstance );
100 HEADER* hdr =
reinterpret_cast<HEADER*
>( srvbuf.buf );
101 unsigned char* here = srvbuf.buf + NS_HFIXEDSZ;
103 if( srvbuf.len < NS_HFIXEDSZ )
106 if( hdr->rcode >= 1 && hdr->rcode <= 5 )
109 if( ntohs( hdr->ancount ) == 0 )
112 if( ntohs( hdr->ancount ) > NS_PACKETSZ )
116 for( cnt = ntohs( hdr->qdcount ); cnt > 0; --cnt )
118 int strlen = dn_skipname( here, srvbuf.buf + srvbuf.len );
119 here += strlen + NS_QFIXEDSZ;
122 unsigned char* srv[NS_PACKETSZ];
124 for( cnt = ntohs( hdr->ancount ); cnt > 0; --cnt )
126 int strlen = dn_skipname( here, srvbuf.buf + srvbuf.len );
128 srv[srvnum++] = here;
130 here += dn_skipname( here, srvbuf.buf + srvbuf.len );
135 return defaultHostMap( domain, logInstance );
141 for( cnt = 0; cnt < srvnum; ++cnt )
143 char srvname[NS_MAXDNAME];
146 if( dn_expand( srvbuf.buf, srvbuf.buf + NS_PACKETSZ,
147 srv[cnt] + SRV_SERVER, srvname, NS_MAXDNAME ) < 0
151 unsigned char* c = srv[cnt] + SRV_PORT;
152 servers.insert( std::make_pair(
static_cast<char*
>( srvname ), ntohs( c[1] << 8 | c[0] ) ) );
155 if( !servers.size() )
156 return defaultHostMap( domain, logInstance );
161 #elif defined( _WIN32 ) && defined( HAVE_WINDNS_H ) && !defined( __MINGW32__ )
163 const std::string& domain,
const LogSink& logInstance )
165 const std::string dname =
"_" + service +
"._" + proto +
"." + domain;
169 DNS_RECORD* pRecord = NULL;
170 DNS_STATUS status = DnsQuery_UTF8( dname.c_str(), DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &pRecord, NULL );
171 if( status == ERROR_SUCCESS )
176 DNS_RECORDA* pRec = (DNS_RECORDA*)pRecord;
179 if( pRec->wType == DNS_TYPE_SRV )
181 servers[pRec->Data.SRV.pNameTarget] = pRec->Data.SRV.wPort;
185 while( pRec != NULL );
186 DnsRecordListFree( pRecord, DnsFreeRecordList );
190 logInstance.
warn(
LogAreaClassDns,
"DnsQuery_UTF8() failed: " + util::int2string( status ) );
194 if( error || !servers.size() )
196 servers = defaultHostMap( domain, logInstance );
204 const std::string& domain,
const LogSink& logInstance )
206 logInstance.warn(
LogAreaClassDns,
"Notice: gloox does not support SRV "
207 "records on this platform. Using A records instead." );
208 return defaultHostMap( domain, logInstance );
212 DNS::HostMap DNS::defaultHostMap(
const std::string& domain,
const LogSink& logInstance )
217 + domain +
", using default port." );
219 if( !domain.empty() )
220 server[domain] = XMPP_PORT;
225 #ifdef HAVE_GETADDRINFO
226 void DNS::resolve(
struct addrinfo** res,
const std::string& service,
const std::string& proto,
227 const std::string& domain,
const LogSink& logInstance )
229 logInstance.dbg(
LogAreaClassDns,
"Resolving: _" + service +
"._" + proto +
"." + domain );
230 struct addrinfo hints;
232 hints.ai_socktype = SOCK_STREAM;
233 else if( proto ==
"udp" )
234 hints.ai_socktype = SOCK_DGRAM;
237 logInstance.err(
LogAreaClassDns,
"Unknown/Invalid protocol: " + proto );
239 memset( &hints,
'\0',
sizeof( hints ) );
240 hints.ai_flags = AI_ADDRCONFIG | AI_CANONNAME;
241 hints.ai_socktype = SOCK_STREAM;
242 int e = getaddrinfo( domain.c_str(), service.c_str(), &hints, res );
249 struct addrinfo* results = 0;
251 resolve( &results, host, logInstance );
258 struct addrinfo* runp = results;
264 freeaddrinfo( results );
268 runp = runp->ai_next;
271 freeaddrinfo( results );
281 int fd =
getSocket( res->ai_family, res->ai_socktype, res->ai_protocol, logInstance );
285 if( ::
connect( fd, res->ai_addr, res->ai_addrlen ) == 0 )
288 char port[NI_MAXSERV];
290 if( getnameinfo( res->ai_addr, res->ai_addrlen,
292 port,
sizeof( port ),
293 NI_NUMERICHOST | NI_NUMERICSERV ) )
299 if( res->ai_canonname )
300 logInstance.
dbg(
LogAreaClassDns, std::string(
"Connecting to " ).append( res->ai_canonname ).append(
" (" ).append( ip ).append(
"), port " ).append( port ) );
302 logInstance.
dbg(
LogAreaClassDns, std::string(
"Connecting to " ).append( ip ).append(
":" ).append( port ) );
307 std::string message =
"connect() failed. "
308 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
309 "WSAGetLastError: " + util::int2string( ::WSAGetLastError() );
311 "errno: " + util::int2string( errno ) +
": " + strerror( errno );
321 int DNS::connect(
const std::string& host,
const LogSink& logInstance )
324 if( hosts.size() == 0 )
327 HostMap::const_iterator it = hosts.begin();
328 for( ; it != hosts.end(); ++it )
330 int fd =
DNS::connect( (*it).first, (*it).second, logInstance );
341 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
343 if( WSAStartup( MAKEWORD( 1, 1 ), &wsaData ) != 0 )
346 + util::int2string( ::WSAGetLastError() ) );
351 int protocol = IPPROTO_TCP;
352 #if !defined( __APPLE__ )
353 struct protoent* prot;
354 if( ( prot = getprotobyname(
"tcp" ) ) != 0 )
356 protocol = prot->p_proto;
360 std::string message =
"getprotobyname( \"tcp\" ) failed. "
361 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
362 "WSAGetLastError: " + util::int2string( ::WSAGetLastError() )
364 "errno: " + util::int2string( errno ) +
": " + strerror( errno );
366 +
". Falling back to IPPROTO_TCP: " + util::int2string( IPPROTO_TCP );
373 return getSocket( PF_INET, SOCK_STREAM, protocol, logInstance );
378 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
383 if( ( fd = socket( af, socktype, proto ) ) == INVALID_SOCKET )
385 std::string message =
"getSocket( "
386 + util::int2string( af ) +
", "
387 + util::int2string( socktype ) +
", "
388 + util::int2string( proto )
390 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
391 "WSAGetLastError: " + util::int2string( ::WSAGetLastError() );
393 "errno: " + util::int2string( errno ) +
": " + strerror( errno );
397 cleanup( logInstance );
401 #ifdef HAVE_SETSOCKOPT
404 setsockopt( fd, SOL_SOCKET, SO_SNDTIMEO,
reinterpret_cast<char*
>( &timeout ),
sizeof( timeout ) );
405 setsockopt( fd, SOL_SOCKET, SO_REUSEADDR,
reinterpret_cast<char*
>( &reuseaddr ),
sizeof( reuseaddr ) );
408 return static_cast<int>( fd );
411 #ifdef HAVE_GETADDRINFO
414 struct addrinfo hints, *servinfo, *p;
418 memset( &hints, 0,
sizeof( hints ) );
419 hints.ai_family = AF_UNSPEC;
420 hints.ai_socktype = SOCK_STREAM;
422 if( ( rv = getaddrinfo( host.c_str(), util::int2string( port ).c_str(), &hints, &servinfo ) ) != 0 )
428 for( p = servinfo; p != 0; p = p->ai_next )
430 if( ( fd =
getSocket( p->ai_family, p->ai_socktype, p->ai_protocol, logInstance ) ) == -1 )
435 if( ::
connect( fd, p->ai_addr, p->ai_addrlen ) == -1 )
446 freeaddrinfo( servinfo );
447 std::string message =
"Connection to " + host +
":" + util::int2string( port ) +
" failed. "
448 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
449 "WSAGetLastError: " + util::int2string( ::WSAGetLastError() );
451 "errno: " + util::int2string( errno ) +
": " + strerror( errno );
457 freeaddrinfo( servinfo );
469 if( ( h = gethostbyname( host.c_str() ) ) == 0 )
472 cleanup( logInstance );
477 struct sockaddr_in target;
478 target.sin_family = AF_INET;
479 target.sin_port = htons(
static_cast<unsigned short int>( port ) );
481 if( h->h_length !=
sizeof(
struct in_addr ) )
484 cleanup( logInstance );
490 memcpy( &target.sin_addr, h->h_addr,
sizeof(
struct in_addr ) );
494 +
" (" + inet_ntoa( target.sin_addr ) +
":" + util::int2string( port ) +
")" );
496 memset( target.sin_zero,
'\0', 8 );
497 if( ::
connect( fd,
reinterpret_cast<struct sockaddr *
>( &target ),
sizeof(
struct sockaddr ) ) == 0 )
500 + inet_ntoa( target.sin_addr ) +
":" + util::int2string( port ) +
")" );
504 std::string message =
"Connection to " + host +
" ("
505 + inet_ntoa( target.sin_addr ) +
":" + util::int2string( port ) +
") failed. "
506 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
507 "WSAGetLastError: " + util::int2string( ::WSAGetLastError() );
509 "errno: " + util::int2string( errno ) +
": " + strerror( errno );
520 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
521 int result = closesocket( fd );
523 int result = close( fd );
528 std::string message =
"closeSocket() failed. "
529 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
530 "WSAGetLastError: " + util::int2string( ::WSAGetLastError() );
532 "errno: " + util::int2string( errno ) +
": " + strerror( errno );
538 void DNS::cleanup(
const LogSink& logInstance )
540 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
541 if( WSACleanup() != 0 )
544 + util::int2string( ::WSAGetLastError() ) );
static int connect(const std::string &host, const LogSink &logInstance)
static HostMap resolve(const std::string &service, const std::string &proto, const std::string &domain, const LogSink &logInstance)
std::map< std::string, int > HostMap
static int getSocket(const LogSink &logInstance)
static void closeSocket(int fd, const LogSink &logInstance)
An implementation of log sink and source.
void warn(LogArea area, const std::string &message) const
void dbg(LogArea area, const std::string &message) const
void err(LogArea area, const std::string &message) const
The namespace for the gloox library.