~ubuntu-branches/ubuntu/vivid/gloox/vivid-proposed

« back to all changes in this revision

Viewing changes to src/linklocalmanager.h

  • Committer: Package Import Robot
  • Author(s): Vincent Cheng
  • Date: 2014-03-16 17:34:43 UTC
  • mfrom: (12.1.2 experimental)
  • mto: This revision was merged to the branch mainline in revision 15.
  • Revision ID: package-import@ubuntu.com-20140316173443-4s177dovzaz5dm8o
Upload to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  Copyright (c) 2012-2013 by Jakob Schroeter <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
#ifndef LINKLOCALMANAGER_H___
 
14
#define LINKLOCALMANAGER_H___
 
15
 
 
16
#include "config.h"
 
17
 
 
18
#ifdef HAVE_MDNS
 
19
 
 
20
#include "linklocal.h"
 
21
#include "macros.h"
 
22
#include "gloox.h"
 
23
#include "util.h"
 
24
#include "logsink.h"
 
25
#include "connectiontcpserver.h"
 
26
#include "mutex.h"
 
27
#include "jid.h"
 
28
 
 
29
#include <string>
 
30
 
 
31
#include <dns_sd.h>
 
32
 
 
33
namespace gloox
 
34
{
 
35
 
 
36
  class ConnectionHandler;
 
37
  class ConnectionTCPClient;
 
38
 
 
39
  namespace LinkLocal
 
40
  {
 
41
 
 
42
    class Handler;
 
43
 
 
44
    /**
 
45
     * @brief This is a manager for server-less messaging (@xep{0174}).
 
46
     *
 
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.
 
51
     *
 
52
     * ### Browsing the local network for XMPP services
 
53
     *
 
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().
 
56
     * @code
 
57
     * m_mdns = new LinkLocal::Manager( ... );
 
58
     * m_mdns->registerLinkLocalHandler( yourHandler );
 
59
     * m_mdns->startBrowsing();
 
60
     * @endcode
 
61
     *
 
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.
 
64
     *
 
65
     * @code
 
66
     * void MyClass::handleBrowseReply( const Service& service )
 
67
     * {
 
68
     *   LinkLocal::ServiceList::const_iterator it = services.begin();
 
69
     *   for( ; it != services.end(); ++it )
 
70
     *   {
 
71
     *     if( (*it).flag == LinkLocal::AddService )
 
72
     *     {
 
73
     *       // new service
 
74
     *     }
 
75
     *     else
 
76
     *     {
 
77
     *       // service removed
 
78
     *     }
 
79
     *   }
 
80
     * }
 
81
     * @endcode
 
82
     *
 
83
     * @note Note that your own service may show up in the list, too.
 
84
     * 
 
85
     * ### Connecting to an XMPP service
 
86
     *
 
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:
 
90
     *
 
91
     * @code
 
92
     * LinkLocal::Client c( JID( "romeo@montague.net" ) );
 
93
     * c.logInstance().registerLogHandler( LogLevelDebug, LogAreaAll, this ); // optional
 
94
     * c.registerConnectionListener( yourConnectionListener );
 
95
     * @endcode
 
96
     *
 
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().
 
99
     *
 
100
     * @code
 
101
     * c.connect( "juliet@laptop", "_presence._tcp", ".local", 4 ); // don't use literal values
 
102
     * @endcode
 
103
     *
 
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.
 
106
     *
 
107
     * ### Advertising an XMPP service on the local network
 
108
     *
 
109
     * To advertise your own XMPP service you can (re-)use the same Manager instance from 'browsing the local network'
 
110
     * above.
 
111
     *
 
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.
 
114
     *
 
115
     * @code
 
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");
 
122
     * @endcode
 
123
     *
 
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().
 
126
     *
 
127
     * @code
 
128
     * m_mdns->registerService();
 
129
     * @endcode
 
130
     *
 
131
     * Other entities on the network will now be informed about the availability of your service.
 
132
     * 
 
133
     * ### Listening for incoming connections
 
134
     *
 
135
     * The second argument to Manager's constructor is a ConnectionHandler-derived class that
 
136
     * will receive incoming connections.
 
137
     * 
 
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.
 
140
     *
 
141
     * In @link gloox::ConnectionHandler::handleIncomingConnection() handleIncomingConnection() @endlink
 
142
     * you should create a new LinkLocal::Client and register some basic handlers:
 
143
     *
 
144
     * @code
 
145
     * LinkLocal::Client c( JID( "romeo@desktop" ) );
 
146
     * c.logInstance().registerLogHandler( LogLevelDebug, LogAreaAll, this );
 
147
     * c.registerMessageHandler( this );
 
148
     * c.registerConnectionListener( this );
 
149
     * @endcode
 
150
     *
 
151
     * Finally you have to attach the incoming connection to the Client instance, and call connect().
 
152
     * 
 
153
     * @code
 
154
     * connection->registerConnectionDataHandler( &c );
 
155
     * c.setConnectionImpl( connection );
 
156
     * c.connect();
 
157
     * @endcode
 
158
     *
 
159
     * Add the Client to your event loop to call recv() periodically.
 
160
     *
 
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.
 
163
     *
 
164
     * @author Jakob Schroeter <js@camaya.net>
 
165
     * @since 1.0.x
 
166
     */
 
167
    class GLOOX_API Manager
 
168
    {
 
169
      
 
170
      public:
 
171
        
 
172
        /**
 
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().
 
179
         */
 
180
        Manager( const std::string& user, ConnectionHandler* connHandler, const LogSink &logInstance );
 
181
 
 
182
        /**
 
183
         * Virtual destructor.
 
184
         * @note @c deregisterService() and @c stopBrowsing() will be called automatically if necessary.
 
185
         */
 
186
        virtual ~Manager();
 
187
 
 
188
        /**
 
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
 
197
         * TXT record.
 
198
         */
 
199
        void addTXTData( const std::string& key, const std::string& value );
 
200
 
 
201
        /**
 
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.
 
207
         */
 
208
        void removeTXTData( const std::string& key );
 
209
 
 
210
        /**
 
211
         * Starts advertising link-local messaging capabilities by publishing a number of DNS records,
 
212
         * as per @xep{0174}.
 
213
         * You can call this function again to publish any values you updated after the first call.
 
214
         */
 
215
        void registerService();
 
216
 
 
217
        /**
 
218
         * Removes the published DNS records and thereby stops advertising link-local messaging
 
219
         * capabilities.
 
220
         */
 
221
        void deregisterService();
 
222
 
 
223
        /**
 
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.
 
228
         */
 
229
        void setUser( const std::string& user ) { m_user = user; }
 
230
 
 
231
        /**
 
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.
 
237
         */
 
238
        void setHost( const std::string& host ) { m_host = host; }
 
239
 
 
240
        /**
 
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().
 
246
         */
 
247
        void setDomain( const std::string& domain ) { m_domain = domain; }
 
248
 
 
249
        /**
 
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.
 
258
         */
 
259
        void setPort( const int port ) { m_port = port; addTXTData( "port.p2pj", util::int2string( m_port ) ); }
 
260
 
 
261
        /**
 
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().
 
271
         */
 
272
        void setInterface( unsigned iface ) { m_interface = iface; }
 
273
 
 
274
        /**
 
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.
 
279
         */
 
280
        bool startBrowsing();
 
281
 
 
282
        /**
 
283
         * Stops the browsing.
 
284
         */
 
285
        void stopBrowsing();
 
286
 
 
287
        /**
 
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.
 
293
         */
 
294
        int socket() const { return m_browseFd; }
 
295
 
 
296
        /**
 
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
 
299
         * is acceptable.
 
300
         */
 
301
        void recv( int timeout );
 
302
 
 
303
        /**
 
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.
 
307
         */
 
308
        void registerLinkLocalHandler( Handler* handler ) { m_linkLocalHandler = handler; }
 
309
 
 
310
//         /**
 
311
//          *
 
312
//          */
 
313
//         static const StringMap decodeTXT( const std::string& txt );
 
314
 
 
315
      private:
 
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 );
 
319
 
 
320
        void handleBrowse( Flag flag, const std::string& service, const std::string& regtype, const std::string& domain, int interface, bool moreComing );
 
321
 
 
322
        typedef std::list<ConnectionTCPClient*> ConnectionList;
 
323
        typedef std::map<ConnectionTCPClient*, const JID> ConnectionMap;
 
324
 
 
325
        DNSServiceRef m_publishRef;
 
326
        DNSServiceRef m_browseRef;
 
327
 
 
328
        ServiceList m_tmpServices;
 
329
//         ServiceList m_services;
 
330
         
 
331
        std::string m_user;
 
332
        std::string m_host;
 
333
        std::string m_domain;
 
334
        unsigned m_interface;
 
335
        int m_port;
 
336
 
 
337
        const LogSink& m_logInstance;
 
338
 
 
339
        int m_browseFd;
 
340
 
 
341
        StringMap m_txtData;
 
342
 
 
343
        ConnectionTCPServer m_server;
 
344
 
 
345
        Handler* m_linkLocalHandler;
 
346
        ConnectionHandler* m_connectionHandler;
 
347
 
 
348
    };
 
349
 
 
350
  }
 
351
 
 
352
}
 
353
 
 
354
#endif // HAVE_MDNS
 
355
 
 
356
#endif // LINKLOCALMANAGER_H___