21 # include <sys/types.h>
26 #if ( !defined( _WIN32 ) && !defined( _WIN32_WCE ) ) || defined( __SYMBIAN32__ )
27 # include <netinet/in.h>
28 # include <arpa/nameser.h>
31 # include <arpa/inet.h>
32 # include <sys/socket.h>
38 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
40 #elif defined( _WIN32_WCE )
41 # include <winsock2.h>
48 #define SRV_COST (RRFIXEDSZ+0)
49 #define SRV_WEIGHT (RRFIXEDSZ+2)
50 #define SRV_PORT (RRFIXEDSZ+4)
51 #define SRV_SERVER (RRFIXEDSZ+6)
52 #define SRV_FIXEDSZ (RRFIXEDSZ+6)
60 # define DNS_TYPE_SRV 33
64 # define NS_CMPRSFLGS 0xc0
71 #ifndef INVALID_SOCKET
72 # define INVALID_SOCKET -1
75 #define XMPP_PORT 5222
80 #if defined( HAVE_RES_QUERYDOMAIN ) && defined( HAVE_DN_SKIPNAME ) && defined( HAVE_RES_QUERY )
82 const std::string& domain,
const LogSink& logInstance )
87 const std::string dname =
"_" + service +
"._" + proto;
90 srvbuf.len = res_querydomain( dname.c_str(),
const_cast<char*
>( domain.c_str() ),
91 C_IN, T_SRV, srvbuf.buf, NS_PACKETSZ );
93 srvbuf.len = res_query( dname.c_str(), C_IN, T_SRV, srvbuf.buf, NS_PACKETSZ );
96 return defaultHostMap( domain, logInstance );
98 HEADER* hdr = (HEADER*)srvbuf.buf;
99 unsigned char* here = srvbuf.buf + NS_HFIXEDSZ;
101 if( srvbuf.len < NS_HFIXEDSZ )
104 if( hdr->rcode >= 1 && hdr->rcode <= 5 )
107 if( ntohs( hdr->ancount ) == 0 )
110 if( ntohs( hdr->ancount ) > NS_PACKETSZ )
114 for( cnt = ntohs( hdr->qdcount ); cnt > 0; --cnt )
116 int strlen = dn_skipname( here, srvbuf.buf + srvbuf.len );
117 here += strlen + NS_QFIXEDSZ;
120 unsigned char* srv[NS_PACKETSZ];
122 for( cnt = ntohs( hdr->ancount ); cnt > 0; --cnt )
124 int strlen = dn_skipname( here, srvbuf.buf + srvbuf.len );
126 srv[srvnum++] = here;
128 here += dn_skipname( here, srvbuf.buf + srvbuf.len );
133 return defaultHostMap( domain, logInstance );
139 for( cnt = 0; cnt < srvnum; ++cnt )
141 char srvname[NS_MAXDNAME];
144 if( dn_expand( srvbuf.buf, srvbuf.buf + NS_PACKETSZ,
145 srv[cnt] + SRV_SERVER, srvname, NS_MAXDNAME ) < 0
149 unsigned char* c = srv[cnt] + SRV_PORT;
150 servers.insert( std::make_pair( (
char*)srvname, ntohs( c[1] << 8 | c[0] ) ) );
153 if( !servers.size() )
154 return defaultHostMap( domain, logInstance );
159 #elif defined( _WIN32 ) && defined( HAVE_WINDNS_H ) && !defined( __MINGW32__ )
161 const std::string& domain,
const LogSink& logInstance )
163 const std::string dname =
"_" + service +
"._" + proto +
"." + domain;
167 DNS_RECORD* pRecord = NULL;
168 DNS_STATUS status = DnsQuery_UTF8( dname.c_str(), DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &pRecord, NULL );
169 if( status == ERROR_SUCCESS )
174 DNS_RECORDA* pRec = (DNS_RECORDA*)pRecord;
177 if( pRec->wType == DNS_TYPE_SRV )
179 servers[pRec->Data.SRV.pNameTarget] = pRec->Data.SRV.wPort;
183 while( pRec != NULL );
184 DnsRecordListFree( pRecord, DnsFreeRecordList );
188 logInstance.warn(
LogAreaClassDns,
"DnsQuery_UTF8() failed: " + util::int2string( status ) );
192 if( error || !servers.size() )
194 servers = defaultHostMap( domain, logInstance );
202 const std::string& domain,
const LogSink& logInstance )
205 "records on this platform. Using A records instead." );
206 return defaultHostMap( domain, logInstance );
215 + domain +
", using default port." );
217 if( !domain.empty() )
218 server[domain] = XMPP_PORT;
223 #ifdef HAVE_GETADDRINFO
224 void DNS::resolve(
struct addrinfo** res,
const std::string& service,
const std::string& proto,
225 const std::string& domain,
const LogSink& logInstance )
227 logInstance.dbg(
LogAreaClassDns,
"Resolving: _" + service +
"._" + proto +
"." + domain );
228 struct addrinfo hints;
230 hints.ai_socktype = SOCK_STREAM;
231 else if( proto ==
"udp" )
232 hints.ai_socktype = SOCK_DGRAM;
235 logInstance.err(
LogAreaClassDns,
"Unknown/Invalid protocol: " + proto );
237 memset( &hints,
'\0',
sizeof( hints ) );
238 hints.ai_flags = AI_ADDRCONFIG | AI_CANONNAME;
239 hints.ai_socktype = SOCK_STREAM;
240 int e = getaddrinfo( domain.c_str(), service.c_str(), &hints, res );
245 int DNS::connect(
const std::string& host,
const LogSink& logInstance )
247 struct addrinfo* results = 0;
249 resolve( &results, host, logInstance );
256 struct addrinfo* runp = results;
263 runp = runp->ai_next;
266 freeaddrinfo( results );
271 int DNS::connect(
struct addrinfo* res,
const LogSink& logInstance )
276 int fd =
getSocket( res->ai_family, res->ai_socktype, res->ai_protocol, logInstance );
280 if( ::
connect( fd, res->ai_addr, res->ai_addrlen ) == 0 )
283 char port[NI_MAXSERV];
285 if( getnameinfo( res->ai_addr,
sizeof( sockaddr ),
287 port,
sizeof( port ),
288 NI_NUMERICHOST | NI_NUMERICSERV ) )
294 if( res->ai_canonname )
295 logInstance.dbg(
LogAreaClassDns, std::string(
"Connecting to " ).append( res->ai_canonname ).append(
" (" ).append( ip ).append(
"), port " ).append( port ) );
297 logInstance.dbg(
LogAreaClassDns, std::string(
"Connecting to " ).append( ip ).append(
":" ).append( port ) );
302 std::string message =
"connect() failed. "
303 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
304 "WSAGetLastError: " + util::int2string( ::WSAGetLastError() );
306 "errno: " + util::int2string( errno ) +
": " + strerror( errno );
319 if( hosts.size() == 0 )
322 HostMap::const_iterator it = hosts.begin();
323 for( ; it != hosts.end(); ++it )
325 int fd =
DNS::connect( (*it).first, (*it).second, logInstance );
336 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
338 if( WSAStartup( MAKEWORD( 1, 1 ), &wsaData ) != 0 )
341 + util::int2string( ::WSAGetLastError() ) );
346 int protocol = IPPROTO_TCP;
347 #if !defined( __APPLE__ ) // Sandboxing on Apple doesn't like you to use getprotobyname
348 struct protoent* prot;
349 if( ( prot = getprotobyname(
"tcp" ) ) != 0 )
351 protocol = prot->p_proto;
355 std::string message =
"getprotobyname( \"tcp\" ) failed. "
356 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
357 "WSAGetLastError: " + util::int2string( ::WSAGetLastError() )
359 "errno: " + util::int2string( errno ) +
": " + strerror( errno );
361 +
". Falling back to IPPROTO_TCP: " + util::int2string( IPPROTO_TCP );
366 #endif // !defined( __APPLE__ )
368 return getSocket( PF_INET, SOCK_STREAM, protocol, logInstance );
373 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
378 if( ( fd = socket( af, socktype, proto ) ) == INVALID_SOCKET )
380 std::string message =
"getSocket( "
381 + util::int2string( af ) +
", "
382 + util::int2string( socktype ) +
", "
383 + util::int2string( proto )
385 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
386 "WSAGetLastError: " + util::int2string( ::WSAGetLastError() );
388 "errno: " + util::int2string( errno ) +
": " + strerror( errno );
392 cleanup( logInstance );
396 #ifdef HAVE_SETSOCKOPT
399 setsockopt( fd, SOL_SOCKET, SO_SNDTIMEO, (
char*)&timeout,
sizeof( timeout ) );
400 setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (
char*)&reuseaddr,
sizeof( reuseaddr ) );
413 if( ( h = gethostbyname( host.c_str() ) ) == 0 )
416 cleanup( logInstance );
421 struct sockaddr_in target;
422 target.sin_family = AF_INET;
423 target.sin_port = htons( static_cast<unsigned short int>( port ) );
425 if( h->h_length !=
sizeof(
struct in_addr ) )
428 cleanup( logInstance );
434 memcpy( &target.sin_addr, h->h_addr,
sizeof(
struct in_addr ) );
438 +
" (" + inet_ntoa( target.sin_addr ) +
":" + util::int2string( port ) +
")" );
440 memset( target.sin_zero,
'\0', 8 );
441 if( ::
connect( fd, (
struct sockaddr *)&target,
sizeof(
struct sockaddr ) ) == 0 )
444 + inet_ntoa( target.sin_addr ) +
":" + util::int2string( port ) +
")" );
448 std::string message =
"Connection to " + host +
" ("
449 + inet_ntoa( target.sin_addr ) +
":" + util::int2string( port ) +
") failed. "
450 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
451 "WSAGetLastError: " + util::int2string( ::WSAGetLastError() );
453 "errno: " + util::int2string( errno ) +
": " + strerror( errno );
463 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
464 int result = closesocket( fd );
466 int result = close( fd );
471 std::string message =
"closeSocket() failed. "
472 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
473 "WSAGetLastError: " + util::int2string( ::WSAGetLastError() );
475 "errno: " + util::int2string( errno ) +
": " + strerror( errno );
481 void DNS::cleanup(
const LogSink& logInstance )
483 #if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
484 if( WSACleanup() != 0 )
487 + util::int2string( ::WSAGetLastError() ) );