linklocalclient.cpp
/*
Copyright (c) 2012-2023 by Jakob Schröter <js@camaya.net>
This file is part of the gloox library. http://camaya.net/gloox
This software is distributed under a license. The full license
agreement can be found in the file LICENSE in this distribution.
This software may not be copied, modified, sold or distributed
other than expressed in the named license agreement.
This software is distributed without any warranty.
*/
#include "linklocalclient.h"
#ifdef HAVE_MDNS
#include "gloox.h"
#include "tag.h"
#include "util.h"
#include "connectiontcpclient.h"
#include <cstdio>
#if ( !defined( _WIN32 ) && !defined( _WIN32_WCE ) ) || defined( __SYMBIAN32__ )
# include <arpa/inet.h>
#endif
#if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
# include <winsock.h>
#elif defined( _WIN32_WCE )
# include <winsock2.h>
#endif
namespace gloox
{
namespace LinkLocal
{
Client::Client( const JID& jid )
: gloox::Client( jid, EmptyString ), m_qRef( 0 ), m_rRef( 0 ), m_currentRef( 0 ),
m_interface( 0 ), m_port( 0 ), m_streamSent( false )
{
}
Client::~Client()
{
}
bool Client::connect()
{
return ClientBase::connect( false );
}
bool Client::connect( const std::string& service, const std::string& type,
const std::string& domain, int iface )
{
m_interface = interface;
return resolve( service, type, domain );
}
ConnectionError Client::recv( int timeout )
{
if( m_connection && m_connection->state() == StateConnected )
return ClientBase::recv( timeout );
else
{
if( !m_currentRef )
return ConnNoError;
struct timeval tv;
fd_set fds;
FD_ZERO( &fds );
// the following causes a C4127 warning in VC++ Express 2008 and possibly other versions.
// however, the reason for the warning can't be fixed in gloox.
FD_SET( DNSServiceRefSockFD( m_currentRef ), &fds );
tv.tv_sec = timeout / 1000000;
tv.tv_usec = timeout % 1000000;
if( select( FD_SETSIZE, &fds, 0, 0, timeout == -1 ? 0 : &tv ) > 0 )
{
if( FD_ISSET( DNSServiceRefSockFD( m_currentRef ), &fds ) != 0 )
DNSServiceProcessResult( m_currentRef );
}
return ConnNoError;
}
}
bool Client::resolve( const std::string& service, const std::string& type,
const std::string& domain )
{
m_to = service;
m_rRef = 0;
DNSServiceErrorType e = DNSServiceResolve( &m_rRef, 0, m_interface, service.c_str(), type.c_str(),
domain.c_str(), (DNSServiceResolveReply)&handleResolveReply, this );
if( e != kDNSServiceErr_NoError )
{
DNSServiceRefDeallocate( m_rRef );
m_rRef = 0;
return false;
}
m_currentRef = m_rRef;
return true;
}
void Client::handleResolveReply( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
DNSServiceErrorType errorCode, const char* fullname, const char* hosttarget,
uint16_t port, uint16_t txtLen, const unsigned char* txtRecord, void* context )
{
if( !context || errorCode != kDNSServiceErr_NoError )
return;
// printf("Client::handleResolveReply susccessful, querying %s\n", hosttarget );
static_cast<Client*>( context )->query( hosttarget, ntohs( port ) );
}
bool Client::query( const std::string& hostname, int port )
{
m_port = port;
m_qRef = 0;
DNSServiceErrorType e = DNSServiceQueryRecord( &m_qRef, 0, m_interface, hostname.c_str(), kDNSServiceType_A,
kDNSServiceClass_IN, (DNSServiceQueryRecordReply)&handleQueryReply, this );
if( e != kDNSServiceErr_NoError )
{
// printf( "Client::query() failed\n" );
DNSServiceRefDeallocate( m_qRef );
m_qRef = 0;
return false;
}
m_currentRef = m_qRef;
return true;
}
void Client::handleQueryReply( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
DNSServiceErrorType errorCode, const char *fullname, uint16_t rrtype,
uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl,
void *context )
{
// printf("Client::handleQueryReply returned\n" );
if( !context || errorCode != kDNSServiceErr_NoError )
return;
const unsigned char* rd = static_cast<const unsigned char*>( rdata );
std::string addr = util::int2string( rd[0] );
addr += '.';
addr += util::int2string( rd[1] );
addr += '.';
addr += util::int2string( rd[2] );
addr += '.';
addr += util::int2string( rd[3] );
// printf( "host %s is at %s\n", fullname, addr.c_str() );
static_cast<Client*>( context )->handleQuery( addr );
}
void Client::handleQuery( const std::string& addr )
{
if( m_rRef )
{
DNSServiceRefDeallocate( m_rRef );
m_rRef = 0;
}
ConnectionTCPClient* connection = new ConnectionTCPClient( this, logInstance(), addr, m_port );
// printf( "LinkLocal::Client: connecting to %s:%d\n", addr.c_str(), m_port );
ConnectionError e = connection->connect();
if( e != ConnNoError )
{
// printf( "connection error: %d\n", e );
delete connection;
}
}
void Client::handleConnect( const ConnectionBase* connection )
{
if( m_qRef )
{
DNSServiceRefDeallocate( m_qRef );
m_qRef = 0;
m_currentRef = 0;
}
// printf( "LinkLocal::Client::handleConnect()!!!\n" );
ConnectionBase* cb = const_cast<ConnectionBase*>( connection );
gloox::Client::setConnectionImpl( cb );
gloox::Client::connect( false );
sendStart( m_to );
}
void Client::handleStartNode( const Tag* start )
{
// printf( "LinkLocal::Client::handleStartNode()\n" );
if( start && !m_streamSent )
sendStart( start->findAttribute( "from" ) );
}
void Client::sendStart( const std::string& to )
{
m_streamSent = true;
std::string s = "<?xml version='1.0' encoding='UTF-8'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='";
s += to;
s += "' from='";
s += m_jid.full().c_str();
s += "' version='1.0'>";
send( s );
}
}
}
#endif // HAVE_MDNS
gloox::ClientBase::port
int port() const
Definition clientbase.h:221
gloox::ClientBase::logInstance
LogSink & logInstance()
Definition clientbase.h:599
gloox::ClientBase::m_jid
JID m_jid
Definition clientbase.h:868
gloox::ClientBase::recv
virtual ConnectionError recv(int timeout=-1)
Definition clientbase.cpp:183
gloox::ClientBase::connect
bool connect(bool block=true)
Definition clientbase.cpp:191
gloox::ClientBase::send
void send(Tag *tag)
Definition clientbase.cpp:1004
gloox::ClientBase::setConnectionImpl
void setConnectionImpl(ConnectionBase *cb)
Definition clientbase.cpp:1199
gloox::ClientBase::jid
const JID & jid()
Definition clientbase.h:147
gloox::ClientBase::m_connection
ConnectionBase * m_connection
Definition clientbase.h:871
gloox::ConnectionBase
An abstract base class for a connection.
Definition connectionbase.h:35
gloox::JID
An abstraction of a JID.
Definition jid.h:31
gloox::JID::full
const std::string & full() const
Definition jid.h:61
gloox::LinkLocal::Client::~Client
virtual ~Client()
Definition linklocalclient.cpp:46
gloox::LinkLocal::Client::recv
virtual ConnectionError recv(int timeout=-1)
Definition linklocalclient.cpp:62
gloox::LinkLocal::Client::handleConnect
virtual void handleConnect(const ConnectionBase *connection)
Definition linklocalclient.cpp:181
gloox::LinkLocal::Client::Client
Client(const JID &jid)
Definition linklocalclient.cpp:40
gloox::LinkLocal::Client::connect
bool connect()
Definition linklocalclient.cpp:50
gloox::LinkLocal::Client::handleStartNode
virtual void handleStartNode(const Tag *start)
Definition linklocalclient.cpp:197
gloox::Tag
This is an abstraction of an XML element.
Definition tag.h:47
gloox::Tag::findAttribute
const std::string & findAttribute(const std::string &name) const
Definition tag.cpp:589
gloox::LinkLocal
Namespace holding all the Link-local-related structures and definitions.
Definition linklocal.h:33
gloox
The namespace for the gloox library.
Definition adhoc.cpp:28
gloox::ConnectionError
ConnectionError
Definition gloox.h:684
gloox::ConnNoError
@ ConnNoError
Definition gloox.h:685
gloox::EmptyString
const std::string EmptyString
Definition gloox.cpp:124
gloox::StateConnected
@ StateConnected
Definition gloox.h:644