gloox 1.0.28
linklocalclient.cpp
1/*
2 Copyright (c) 2012-2023 by Jakob Schröter <js@camaya.net>
3 This file is part of the gloox library. http://camaya.net/gloox
4
5 This software is distributed under a license. The full license
6 agreement can be found in the file LICENSE in this distribution.
7 This software may not be copied, modified, sold or distributed
8 other than expressed in the named license agreement.
9
10 This software is distributed without any warranty.
11*/
12
13#include "linklocalclient.h"
14
15#ifdef HAVE_MDNS
16
17#include "gloox.h"
18#include "tag.h"
19#include "util.h"
20#include "connectiontcpclient.h"
21
22#include <cstdio>
23
24#if ( !defined( _WIN32 ) && !defined( _WIN32_WCE ) ) || defined( __SYMBIAN32__ )
25# include <arpa/inet.h>
26#endif
27
28#if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
29# include <winsock.h>
30#elif defined( _WIN32_WCE )
31# include <winsock2.h>
32#endif
33
34namespace gloox
35{
36
37 namespace LinkLocal
38 {
39
40 Client::Client( const JID& jid )
41 : gloox::Client( jid, EmptyString ), m_qRef( 0 ), m_rRef( 0 ), m_currentRef( 0 ),
42 m_interface( 0 ), m_port( 0 ), m_streamSent( false )
43 {
44 }
45
47 {
48 }
49
51 {
52 return ClientBase::connect( false );
53 }
54
55 bool Client::connect( const std::string& service, const std::string& type,
56 const std::string& domain, int iface )
57 {
58 m_interface = interface;
59 return resolve( service, type, domain );
60 }
61
63 {
65 return ClientBase::recv( timeout );
66 else
67 {
68 if( !m_currentRef )
69 return ConnNoError;
70
71 struct timeval tv;
72
73 fd_set fds;
74 FD_ZERO( &fds );
75 // the following causes a C4127 warning in VC++ Express 2008 and possibly other versions.
76 // however, the reason for the warning can't be fixed in gloox.
77 FD_SET( DNSServiceRefSockFD( m_currentRef ), &fds );
78
79 tv.tv_sec = timeout / 1000000;
80 tv.tv_usec = timeout % 1000000;
81
82 if( select( FD_SETSIZE, &fds, 0, 0, timeout == -1 ? 0 : &tv ) > 0 )
83 {
84 if( FD_ISSET( DNSServiceRefSockFD( m_currentRef ), &fds ) != 0 )
85 DNSServiceProcessResult( m_currentRef );
86 }
87
88 return ConnNoError;
89 }
90 }
91
92
93 bool Client::resolve( const std::string& service, const std::string& type,
94 const std::string& domain )
95 {
96 m_to = service;
97 m_rRef = 0;
98 DNSServiceErrorType e = DNSServiceResolve( &m_rRef, 0, m_interface, service.c_str(), type.c_str(),
99 domain.c_str(), (DNSServiceResolveReply)&handleResolveReply, this );
100 if( e != kDNSServiceErr_NoError )
101 {
102 DNSServiceRefDeallocate( m_rRef );
103 m_rRef = 0;
104 return false;
105 }
106 m_currentRef = m_rRef;
107
108 return true;
109 }
110
111 void Client::handleResolveReply( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
112 DNSServiceErrorType errorCode, const char* fullname, const char* hosttarget,
113 uint16_t port, uint16_t txtLen, const unsigned char* txtRecord, void* context )
114 {
115 if( !context || errorCode != kDNSServiceErr_NoError )
116 return;
117
118 // printf("Client::handleResolveReply susccessful, querying %s\n", hosttarget );
119
120 static_cast<Client*>( context )->query( hosttarget, ntohs( port ) );
121 }
122
123 bool Client::query( const std::string& hostname, int port )
124 {
125 m_port = port;
126 m_qRef = 0;
127 DNSServiceErrorType e = DNSServiceQueryRecord( &m_qRef, 0, m_interface, hostname.c_str(), kDNSServiceType_A,
128 kDNSServiceClass_IN, (DNSServiceQueryRecordReply)&handleQueryReply, this );
129 if( e != kDNSServiceErr_NoError )
130 {
131 // printf( "Client::query() failed\n" );
132 DNSServiceRefDeallocate( m_qRef );
133 m_qRef = 0;
134 return false;
135 }
136 m_currentRef = m_qRef;
137
138 return true;
139 }
140
141 void Client::handleQueryReply( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
142 DNSServiceErrorType errorCode, const char *fullname, uint16_t rrtype,
143 uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl,
144 void *context )
145 {
146 // printf("Client::handleQueryReply returned\n" );
147
148 if( !context || errorCode != kDNSServiceErr_NoError )
149 return;
150
151 const unsigned char* rd = static_cast<const unsigned char*>( rdata );
152 std::string addr = util::int2string( rd[0] );
153 addr += '.';
154 addr += util::int2string( rd[1] );
155 addr += '.';
156 addr += util::int2string( rd[2] );
157 addr += '.';
158 addr += util::int2string( rd[3] );
159 // printf( "host %s is at %s\n", fullname, addr.c_str() );
160 static_cast<Client*>( context )->handleQuery( addr );
161 }
162
163 void Client::handleQuery( const std::string& addr )
164 {
165 if( m_rRef )
166 {
167 DNSServiceRefDeallocate( m_rRef );
168 m_rRef = 0;
169 }
170
171 ConnectionTCPClient* connection = new ConnectionTCPClient( this, logInstance(), addr, m_port );
172 // printf( "LinkLocal::Client: connecting to %s:%d\n", addr.c_str(), m_port );
173 ConnectionError e = connection->connect();
174 if( e != ConnNoError )
175 {
176 // printf( "connection error: %d\n", e );
177 delete connection;
178 }
179 }
180
181 void Client::handleConnect( const ConnectionBase* connection )
182 {
183 if( m_qRef )
184 {
185 DNSServiceRefDeallocate( m_qRef );
186 m_qRef = 0;
187 m_currentRef = 0;
188 }
189
190 // printf( "LinkLocal::Client::handleConnect()!!!\n" );
191 ConnectionBase* cb = const_cast<ConnectionBase*>( connection );
193 gloox::Client::connect( false );
194 sendStart( m_to );
195 }
196
197 void Client::handleStartNode( const Tag* start )
198 {
199 // printf( "LinkLocal::Client::handleStartNode()\n" );
200 if( start && !m_streamSent )
201 sendStart( start->findAttribute( "from" ) );
202 }
203
204 void Client::sendStart( const std::string& to )
205 {
206 m_streamSent = true;
207 std::string s = "<?xml version='1.0' encoding='UTF-8'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='";
208 s += to;
209 s += "' from='";
210 s += m_jid.full().c_str();
211 s += "' version='1.0'>";
212 send( s );
213 }
214
215 }
216
217}
218
219#endif // HAVE_MDNS
int port() const
Definition clientbase.h:221
LogSink & logInstance()
Definition clientbase.h:599
virtual ConnectionError recv(int timeout=-1)
bool connect(bool block=true)
void send(Tag *tag)
void setConnectionImpl(ConnectionBase *cb)
ConnectionBase * m_connection
Definition clientbase.h:871
An abstract base class for a connection.
ConnectionState state() const
An abstraction of a JID.
Definition jid.h:31
const std::string & full() const
Definition jid.h:61
An implementation of a link-local client.
virtual ConnectionError recv(int timeout=-1)
virtual void handleConnect(const ConnectionBase *connection)
virtual void handleStartNode(const Tag *start)
This is an abstraction of an XML element.
Definition tag.h:47
const std::string & findAttribute(const std::string &name) const
Definition tag.cpp:589
The namespace for the gloox library.
Definition adhoc.cpp:28
ConnectionError
Definition gloox.h:684
@ ConnNoError
Definition gloox.h:685
const std::string EmptyString
Definition gloox.cpp:124
@ StateConnected
Definition gloox.h:644