2
Copyright (c) 2012-2013 by Jakob Schroeter <js@camaya.net>
3
This file is part of the gloox library. http://camaya.net/gloox
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.
10
This software is distributed without any warranty.
13
#ifndef LINKLOCALMANAGER_H___
14
#define LINKLOCALMANAGER_H___
20
#include "linklocal.h"
25
#include "connectiontcpserver.h"
36
class ConnectionHandler;
37
class ConnectionTCPClient;
45
* @brief This is a manager for server-less messaging (@xep{0174}).
47
* Enable compilation of this code with the @c \-\-enable-mdns switch to @c configure, or add
48
* @c \#define @c HAVE_MDNS to your platform's @c config.h. @c dns_sd.h, @c libdns_sd.so, as well
49
* as the @c mdnsd daemon from Apple's bonjour distribution are required. The @c mdnsd daemon has
50
* to be running on the local host.
52
* ### Browsing the local network for XMPP services
54
* You can use the Manager to browse the local network for XMPP services.
55
* First, create a new instance, register a LinkLocal::Handler, and call startBrowsing().
57
* m_mdns = new LinkLocal::Manager( ... );
58
* m_mdns->registerLinkLocalHandler( yourHandler );
59
* m_mdns->startBrowsing();
62
* Then you will need to call @c recv() periodcally. The handler will then receive lists of available
63
* or removed services. Check the @c flag member of the Service struct.
66
* void MyClass::handleBrowseReply( const Service& service )
68
* LinkLocal::ServiceList::const_iterator it = services.begin();
69
* for( ; it != services.end(); ++it )
71
* if( (*it).flag == LinkLocal::AddService )
83
* @note Note that your own service may show up in the list, too.
85
* ### Connecting to an XMPP service
87
* Using the info from the Service struct you can initiate a connection to the remote entity.
88
* First, create a new instance of LinkLocal::Client and register some basic handlers like you
89
* would with a normal gloox::Client:
92
* LinkLocal::Client c( JID( "romeo@montague.net" ) );
93
* c.logInstance().registerLogHandler( LogLevelDebug, LogAreaAll, this ); // optional
94
* c.registerConnectionListener( yourConnectionListener );
97
* Then call @link gloox::LinkLocal::Client::connect( const std::string&, const std::string&, const std::string&, int ) connect() @endlink
98
* and pass the paramters from the Service struct that you received in handleBrowseReply().
101
* c.connect( "juliet@laptop", "_presence._tcp", ".local", 4 ); // don't use literal values
104
* Put your LinkLocal::Client instance in your event loop (or in a separate thread) and call
105
* @link gloox::LinkLocal::Client::recv() recv() @endlink periodically.
107
* ### Advertising an XMPP service on the local network
109
* To advertise your own XMPP service you can (re-)use the same Manager instance from 'browsing the local network'
112
* You can publish some basic info about your service in a DNS TXT record. The Manager offers the addTXTData() function
113
* for that. See http://xmpp.org/registrar/linklocal.html for a list of official parameters.
116
* m_mdns->addTXTData("nick","July");
117
* m_mdns->addTXTData("1st","Juliet");
118
* m_mdns->addTXTData("last","Capulet");
119
* m_mdns->addTXTData("msg","Hanging out");
120
* m_mdns->addTXTData("jid","julia@capulet.com");
121
* m_mdns->addTXTData("status","avail");
124
* Then, to start publishing the availability of your service as well as the TXT record with the additional info
125
* you just call @c registerService().
128
* m_mdns->registerService();
131
* Other entities on the network will now be informed about the availability of your service.
133
* ### Listening for incoming connections
135
* The second argument to Manager's constructor is a ConnectionHandler-derived class that
136
* will receive incoming connections.
138
* When registerService() gets called, the Manager will also start a local server that will
139
* accept incoming connections. By default, it will listen on port 5562.
141
* In @link gloox::ConnectionHandler::handleIncomingConnection() handleIncomingConnection() @endlink
142
* you should create a new LinkLocal::Client and register some basic handlers:
145
* LinkLocal::Client c( JID( "romeo@desktop" ) );
146
* c.logInstance().registerLogHandler( LogLevelDebug, LogAreaAll, this );
147
* c.registerMessageHandler( this );
148
* c.registerConnectionListener( this );
151
* Finally you have to attach the incoming connection to the Client instance, and call connect().
154
* connection->registerConnectionDataHandler( &c );
155
* c.setConnectionImpl( connection );
159
* Add the Client to your event loop to call recv() periodically.
161
* @see @c linklocal_example.cpp in @c src/examples/ for a (very) simple implementation of a bot
162
* handling both incoming and outgoing connections.
164
* @author Jakob Schroeter <js@camaya.net>
167
class GLOOX_API Manager
173
* Creates a new Link-local Manager instance. You can call @c registerService() and/or @c startBrowsing()
174
* immediately on a new Manager object, it will use sane defaults.
175
* @param user The username to advertise, preferably (as per @xep{0174}) the locally
176
* logged-in user. This is just the local part of the local JID.
177
* @param connHandler A pointer to a ConnectionHandler that will receive incoming connections.
178
* @param logInstance The log target. Obtain it from ClientBase::logInstance().
180
Manager( const std::string& user, ConnectionHandler* connHandler, const LogSink &logInstance );
183
* Virtual destructor.
184
* @note @c deregisterService() and @c stopBrowsing() will be called automatically if necessary.
189
* Lets you add additional data to the published TXT record.
190
* @note The @c txtvers=1 parameter is included by default and cannot be changed.
191
* @param key The key of a key=value parameter pair. Must be non-empty. If the given key
192
* has been set before, its value will be overwritten by the new value.
193
* @param value The value of a @c key=value parameter pair. Must be non-empty.
194
* @note If either parameter is empty, this function is a NOOP.
195
* @note The additional data will not be automatically published if you have already called
196
* @c registerService(). You will have to call @c registerService() again to update the
199
void addTXTData( const std::string& key, const std::string& value );
202
* Lets you remove TXT record data by key.
203
* @note The @c txtvers=1 parameter is included by default and cannot be removed.
204
* @param key The key of the @c key=value parameter pair that should be removed. Must be non-empty.
205
* @note A published TXT record will not be automatically updated if you have already called
206
* @c registerService(). You will have to call @c registerService() again to update the TXT record.
208
void removeTXTData( const std::string& key );
211
* Starts advertising link-local messaging capabilities by publishing a number of DNS records,
213
* You can call this function again to publish any values you updated after the first call.
215
void registerService();
218
* Removes the published DNS records and thereby stops advertising link-local messaging
221
void deregisterService();
224
* Lets you specify a new username.
225
* @param user The new username.
226
* @note The new username will not be automatically advertised if you have already called
227
* @c registerService(). You will have to call @c registerService() again to update the username.
229
void setUser( const std::string& user ) { m_user = user; }
232
* Lets you specify an alternate host name to advertise. By default the local machine's hostname
233
* as returned by @c gethostname() will be used.
234
* @param host The hostname to use.
235
* @note The new hostname will not be automatically advertised if you have already called
236
* @c registerService(). You will have to call @c registerService() again to update the hostname.
238
void setHost( const std::string& host ) { m_host = host; }
241
* This function lets you set an alternate browse domain. The default domain should work in most cases.
242
* @param domain The browse domain to set.
243
* @note The new domain will not be automatically used if you have already called
244
* @c registerService(). You will have to call @c registerService() again to update the domain.
245
* The same applies to @c startBrowsing().
247
void setDomain( const std::string& domain ) { m_domain = domain; }
250
* Lets you specifiy a port to listen on for incoming server-less XMPP connections. Default
251
* for this implementation is port 5562, but any unused port can be used.
252
* @note In addition to the SRV record, the port will also be published in the TXT record
253
* automaticlly, you do not have to add it manually. That is, you should not call
254
* @c addTXTData() with a key of @c "port.p2pj".
255
* @param port The port to use.
256
* @note The new port will not be automatically advertised if you have already called
257
* @c registerService(). You will have to call @c registerService() again to update the port.
259
void setPort( const int port ) { m_port = port; addTXTData( "port.p2pj", util::int2string( m_port ) ); }
262
* This function can be used to set a non-default interface. Use @c if_nametoindex() to
263
* find the index for a specific named device.
264
* By default DNS records will be broadcast on all available interfaces, and all available
265
* interfaces will be used or browsing services.
266
* @param iface The interface to use. If you set an interface here, and want to change it
267
* back to 'any', use @b 0. Use @b -1 to broadcast only on the local machine.
268
* @note The new interface will not be automatically used if you have already called
269
* @c registerService(). You will have to call @c registerService() again to use the new
270
* interface. The same applies to @c startBrowsing().
272
void setInterface( unsigned iface ) { m_interface = iface; }
275
* Starts looking for other entities of type @c _presence. You have to set a handler for
276
* results using @c registerLinkLocalHandler() before calling this function.
277
* You can call this function again to re-start browsing with updated parameters.
278
* @return Returns @b true if browsing could be started successfully, @b false otherwise.
280
bool startBrowsing();
283
* Stops the browsing.
288
* Exposes the socket used for browsing so you can have it checked in your own event loop,
289
* if desired. If your event loop signals new data on the socket, you should NOT
290
* try to read from it directly. Instead you should call @c recv().
291
* As an alternative to using the raw socket you could also put the Manager in a
292
* separate thread and call @c recv() repeatedly, or achieve this in any other way.
294
int socket() const { return m_browseFd; }
297
* Checks once for new data on the socket used for browsing.
298
* @param timeout The timeout for @c select() in microseconds. Use @b -1 if blocking behavior
301
void recv( int timeout );
304
* Registers a handler that will be notfied about entities found on the network that match
305
* the given browse criteria.
306
* @param handler The handler to register.
308
void registerLinkLocalHandler( Handler* handler ) { m_linkLocalHandler = handler; }
313
// static const StringMap decodeTXT( const std::string& txt );
316
static void handleBrowseReply( DNSServiceRef sdRef, DNSServiceFlags flags, unsigned interfaceIndex,
317
DNSServiceErrorType errorCode, const char* serviceName, const char* regtype,
318
const char* replyDomain, void* context );
320
void handleBrowse( Flag flag, const std::string& service, const std::string& regtype, const std::string& domain, int interface, bool moreComing );
322
typedef std::list<ConnectionTCPClient*> ConnectionList;
323
typedef std::map<ConnectionTCPClient*, const JID> ConnectionMap;
325
DNSServiceRef m_publishRef;
326
DNSServiceRef m_browseRef;
328
ServiceList m_tmpServices;
329
// ServiceList m_services;
333
std::string m_domain;
334
unsigned m_interface;
337
const LogSink& m_logInstance;
343
ConnectionTCPServer m_server;
345
Handler* m_linkLocalHandler;
346
ConnectionHandler* m_connectionHandler;
356
#endif // LINKLOCALMANAGER_H___