gloox 1.0.27
linklocalmanager.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 "linklocalmanager.h"
14
15#ifdef HAVE_MDNS
16
17#include "linklocalhandler.h"
18#include "connectiontcpclient.h"
19#include "jid.h"
20#include "util.h"
21
22#include <cstdio>
23
24#if ( !defined( _WIN32 ) && !defined( _WIN32_WCE ) ) || defined( __SYMBIAN32__ )
25# include <unistd.h>
26# include <arpa/inet.h>
27#endif
28
29#if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
30# include <winsock.h>
31#elif defined( _WIN32_WCE )
32# include <winsock2.h>
33#endif
34
35#define LINKLOCAL_SERVICE_PORT 5562
36
37const std::string LINKLOCAL_SERVICE_TYPE = "_presence._tcp";
38
39namespace gloox
40{
41
42 namespace LinkLocal
43 {
44
45 Manager::Manager( const std::string& user, ConnectionHandler* connHandler, const LogSink &logInstance )
46 : m_publishRef( 0 ), m_browseRef( 0 ), m_user( user ), m_interface( 0 ), m_port( 0 ),
47 m_logInstance( logInstance ), m_browseFd( 0 ), m_server( connHandler, m_logInstance, EmptyString, LINKLOCAL_SERVICE_PORT ),
48 m_linkLocalHandler( 0 ), m_connectionHandler( connHandler )
49 {
50
51 setPort( LINKLOCAL_SERVICE_PORT ); // does more than just setting m_port
52 addTXTData( "node", GLOOX_CAPS_NODE );
53 }
54
56 {
59 }
60
61 void Manager::addTXTData( const std::string& key, const std::string& value )
62 {
63 if( value.empty() || key.empty() || key == "txtvers" )
64 return;
65
66 m_txtData[key] = value;
67 }
68
69 void Manager::removeTXTData( const std::string& key )
70 {
71 m_txtData.erase( key );
72 }
73
75 {
76 if( m_publishRef )
78
79 m_server.connect();
80
81 std::string txtRecord;
82 txtRecord += (char)9; // length of mandatory txtvers=1
83 txtRecord += "txtvers=1"; // this is here because it SHOULD be the first entry
84 StringMap::const_iterator it = m_txtData.begin();
85 for( ; it != m_txtData.end(); ++it )
86 {
87 txtRecord += (char)( (*it).first.length() + (*it).second.length() + 1 );
88 txtRecord += (*it).first;
89 txtRecord += '=';
90 txtRecord += (*it).second;
91 }
92
93 std::string service = m_user + "@";
94 if( m_host.empty() )
95 {
96 char host[65];
97 gethostname( host, 65 );
98 service += host;
99 }
100 else
101 service += m_host;
102
103 /*DNSServiceErrorType e =*/ DNSServiceRegister( &m_publishRef,
104 0, // flags
105 m_interface, // interface, 0 = any, -1 = local only
106 service.c_str(), // service name, 0 = local computer name
107 LINKLOCAL_SERVICE_TYPE.c_str(), // service type
108 m_domain.c_str(), // domain, 0 = default domain(s)
109 m_host.c_str(), // host, 0 = default host name(s)
110 htons( m_port ), // port
111 (short unsigned int)txtRecord.length(), // TXT record length
112 (const void*)txtRecord.c_str(), // TXT record
113 0, // callback
114 0 ); // context
115 }
116
118 {
119 if( m_publishRef )
120 {
121 DNSServiceRefDeallocate( m_publishRef );
122 m_publishRef = 0;
123 }
124 }
125
127 {
128 if( !m_linkLocalHandler )
129 return false;
130
131 if( m_browseRef )
132 stopBrowsing();
133
134 DNSServiceErrorType e = DNSServiceBrowse( &m_browseRef,
135 0, // flags, currently ignored
136 m_interface, // interface, 0 = any, -1 = local only
137 LINKLOCAL_SERVICE_TYPE.c_str(), // service type
138 m_domain.c_str(), // domain, 0 = default domain(s)
139 &handleBrowseReply, // callback
140 this ); // context
141 if ( e != kDNSServiceErr_NoError )
142 return false;
143
144 return true;
145 }
146
148 {
149 if( m_browseRef )
150 {
151 DNSServiceRefDeallocate( m_browseRef );
152 m_browseRef = 0;
153 }
154 }
155
156 void Manager::recv( int timeout )
157 {
158 if( !m_browseRef )
159 return;
160
161 struct timeval tv;
162
163 fd_set fds;
164 FD_ZERO( &fds );
165 // the following causes a C4127 warning in VC++ Express 2008 and possibly other versions.
166 // however, the reason for the warning can't be fixed in gloox.
167 FD_SET( DNSServiceRefSockFD( m_browseRef ), &fds );
168
169 tv.tv_sec = timeout / 1000000;
170 tv.tv_usec = timeout % 1000000;
171
172 if( select( FD_SETSIZE, &fds, 0, 0, timeout == -1 ? 0 : &tv ) > 0 )
173 {
174 if( FD_ISSET( DNSServiceRefSockFD( m_browseRef ), &fds ) != 0 )
175 DNSServiceProcessResult( m_browseRef );
176 }
177
178 m_server.recv( timeout );
179 }
180
181
182 void Manager::handleBrowseReply( DNSServiceRef /*sdRef*/, DNSServiceFlags flags, uint32_t interfaceIndex,
183 DNSServiceErrorType errorCode, const char* serviceName, const char* regtype,
184 const char* replyDomain, void* context )
185 {
186 if( !context || errorCode != kDNSServiceErr_NoError )
187 return;
188
189 Flag f = ( flags & kDNSServiceFlagsAdd ) == kDNSServiceFlagsAdd
190 ? AddService
192
193 Manager* m = static_cast<Manager*>( context );
194 m->handleBrowse( f, serviceName, regtype, replyDomain, interfaceIndex, ( flags & kDNSServiceFlagsMoreComing ) == kDNSServiceFlagsMoreComing );
195
196 }
197
198 void Manager::handleBrowse( Flag flag, const std::string& service, const std::string& regtype, const std::string& domain, int iface, bool moreComing )
199 {
200 Service s( flag, service, regtype, domain, interface );
201 m_tmpServices.push_back( s );
202
203// switch( flag )
204// {
205// case AddService:
206// {
207// m_services.push_back( s );
208// break;
209// }
210// case RemoveService:
211// {
212// ServiceList::iterator it = m_services.begin();
213// for( ; it != m_services.end(); ++it )
214// {
215// if( (*it)->service == service && (*it)->regtype == regtype && (*it)->domain == domain )
216// {
217// m_services.erase( it );
218// }
219// }
220// break;
221// }
222// }
223
224 if( !moreComing )
225 {
226 m_linkLocalHandler->handleBrowseReply( m_tmpServices );
227 m_tmpServices.clear();
228 }
229 }
230
231
232// const StringMap Manager::decodeTXT( const std::string& txt )
233// {
234// StringMap result;
235// if( txt.empty() )
236// return result;
237//
238// std::string::const_iterator it = txt.begin();
239// while( it < txt.end() )
240// {
241// int len = (int)(*it);
242// std::string tmp( ++it, it + len + 1 );
243// it += len;
244// size_t pos = tmp.find( '=' );
245// result.insert( std::make_pair( tmp.substr( 0, pos ), tmp.substr( pos + 1 ) ) );
246// }
247//
248// return result;
249// }
250
251 }
252
253}
254
255#endif // HAVE_MDNS
This is an abstract base class to receive incoming connection attempts. Do not confuse this with Conn...
virtual ConnectionError recv(int timeout=-1)
virtual ConnectionError connect()
virtual void handleBrowseReply(const ServiceList &services)=0
This is a manager for server-less messaging (XEP-0174).
void removeTXTData(const std::string &key)
void setPort(const int port)
Manager(const std::string &user, ConnectionHandler *connHandler, const LogSink &logInstance)
void addTXTData(const std::string &key, const std::string &value)
An implementation of log sink and source.
Definition: logsink.h:39
The namespace for the gloox library.
Definition: adhoc.cpp:28
const std::string GLOOX_CAPS_NODE
Definition: gloox.cpp:120
const std::string EmptyString
Definition: gloox.cpp:124