An Overlay-based
Virtual Network Substrate
SpoVNet

source: source/ariba/utility/bootstrap/modules/multicastdns/MulticastDns.cpp @ 7532

Last change on this file since 7532 was 7532, checked in by mayer, 9 years ago

-von außen konfigurierbare bootstrap module, -periodicbroadcast crash fix

File size: 11.9 KB
Line 
1
2// [License]
3// The Ariba-Underlay Copyright
4//
5// Copyright (c) 2008-2009, Institute of Telematics, UniversitÀt Karlsruhe (TH)
6//
7// Institute of Telematics
8// UniversitÀt Karlsruhe (TH)
9// Zirkel 2, 76128 Karlsruhe
10// Germany
11//
12// Redistribution and use in source and binary forms, with or without
13// modification, are permitted provided that the following conditions are
14// met:
15//
16// 1. Redistributions of source code must retain the above copyright
17// notice, this list of conditions and the following disclaimer.
18// 2. Redistributions in binary form must reproduce the above copyright
19// notice, this list of conditions and the following disclaimer in the
20// documentation and/or other materials provided with the distribution.
21//
22// THIS SOFTWARE IS PROVIDED BY THE INSTITUTE OF TELEMATICS ``AS IS'' AND
23// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ARIBA PROJECT OR
26// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33//
34// The views and conclusions contained in the software and documentation
35// are those of the authors and should not be interpreted as representing
36// official policies, either expressed or implied, of the Institute of
37// Telematics.
38// [License]
39
40#include "MulticastDns.h"
41
42namespace ariba {
43namespace utility {
44
45const string MulticastDns::serviceType = "_spovnet._tcp";
46use_logging_cpp(MulticastDns);
47
48MulticastDns::MulticastDns(BootstrapInformationCallback* _callback, string info)
49        : BootstrapModule(_callback) {
50  #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
51        avahiclient = NULL;
52        avahipoll = NULL;
53        avahibrowser = NULL;
54  #endif // HAVE_AVAHI_CLIENT_CLIENT_H
55}
56
57MulticastDns::~MulticastDns(){
58}
59
60string MulticastDns::getName(){
61        return "MulticastDns";
62}
63
64string MulticastDns::getInformation(){
65        return "bootstrap module based on multicast-dns using the avahi library";
66}
67
68bool MulticastDns::isFunctional(){
69  #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
70        return true;
71  #else
72        return false;
73  #endif
74}
75
76void MulticastDns::start(){
77  #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
78
79        int error = 0;
80
81        // create a new avahi polling thread
82        avahipoll = avahi_threaded_poll_new();
83        if( avahipoll == NULL){
84                logging_error("creating avahi poll failed");
85                return;
86        }
87
88        // create a new avahi client
89        avahiclient = avahi_client_new(
90                        avahi_threaded_poll_get(avahipoll),
91                        (AvahiClientFlags)0,
92                        MulticastDns::client_callback,
93                        this,
94                        &error
95                        );
96
97        if( avahiclient == NULL){
98                logging_error("creating avahi client failed with error "<<
99                                error << ". make sure that the avahi-daemon is running. e.g. by installing avahi-utils");
100                return;
101        }
102
103        // block the event loop
104        avahi_threaded_poll_lock( avahipoll );
105
106        // create the service browser for the specified type
107        avahibrowser = avahi_service_browser_new(
108                        avahiclient, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
109                        serviceType.c_str(), NULL,
110                        (AvahiLookupFlags)0, MulticastDns::browse_callback, this);
111
112        if( avahibrowser == NULL){
113                logging_error("creating avahi browser failed");
114                return;
115        }
116
117        //unblock the event loop and let it run
118        avahi_threaded_poll_unlock( avahipoll );
119        avahi_threaded_poll_start( avahipoll );
120
121  #endif // HAVE_AVAHI_CLIENT_CLIENT_H
122}
123
124void MulticastDns::stop(){
125  #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
126
127        //
128        // stop poll and free browser
129        //
130
131        avahi_threaded_poll_stop( avahipoll );
132        avahi_service_browser_free( avahibrowser );
133        avahibrowser = NULL;
134
135        //
136        // free all registered groups
137        //
138
139        AvahiGroupMap::iterator i = avahigroups.begin();
140        AvahiGroupMap::iterator iend = avahigroups.end();
141
142        for( ; i != iend; i++)
143                avahi_entry_group_free( i->second );
144
145        //
146        // free client and poll
147        //
148
149        if(avahiclient != NULL)
150                avahi_client_free( avahiclient );
151        avahiclient = NULL;
152
153        if(avahipoll != NULL)
154                avahi_threaded_poll_free( avahipoll );
155        avahipoll = NULL;
156
157  #endif // HAVE_AVAHI_CLIENT_CLIENT_H
158}
159
160void MulticastDns::publishService(string name, string info1, string info2, string info3){
161  #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
162
163        if(name.length() > 63){
164                logging_error("service name length must not exceed 63 characters. "
165                                << name << " is " << name.length() << " characters");
166                return;
167        }
168
169        if( avahiclient == NULL ){
170                logging_error("avahi client is invalid");
171                return;
172        }
173
174        avahi_threaded_poll_lock(avahipoll);
175        int ret = 0;
176
177        //
178        // if we have no group for this service, create one
179        //
180
181        AvahiGroupMap::iterator igroup = avahigroups.find(name);
182        AvahiEntryGroup* currentgroup = (igroup != avahigroups.end() ? igroup->second : NULL);
183
184        if( currentgroup == NULL ){
185
186                logging_debug("creating group for service " << name);
187                currentgroup = avahi_entry_group_new(avahiclient, MulticastDns::entry_group_callback, this);
188
189                if(currentgroup == NULL){
190                        logging_error("failed creating avahi group for service "
191                                        << name << ": " << avahi_strerror(avahi_client_errno(avahiclient)));
192                        avahi_threaded_poll_unlock(avahipoll);
193                        return;
194                }
195
196                avahigroups.insert( make_pair(name, currentgroup) );
197        }
198
199        assert( currentgroup != NULL );
200
201        logging_debug("avahi adding service " << name << " to new group");
202
203        ret = avahi_entry_group_add_service(
204                        currentgroup,                   // group to add service to
205                        AVAHI_IF_UNSPEC,                // interface to announce, we use all interfaces
206                        AVAHI_PROTO_UNSPEC,     // protocol to announce, we use all protocols
207                        (AvahiPublishFlags)0,   // no special flags
208                        name.c_str(),                   // name of the service, no more than 63 characters
209                        serviceType.c_str(),    // type of the service: _spovnet._tcp (tcp does not mean anything here, just have to stick with this structure
210                        NULL,                                   // publish in all domains
211                        NULL,                                   // host name of our machine, let avahi find out
212                        3333,                                   // port number the service is on, just dummy, everything is encoded in TXT
213                        info1.c_str(),                  // arbitrary info
214                        info2.c_str(),                  // arbitrary info
215                        info3.c_str(),                  // arbitrary info
216                        NULL);                                  // make that this is the last info field
217
218        if( ret < 0 ){
219                logging_warn("failed to add service " << name << ": " << avahi_strerror(ret));
220                avahigroups.erase(name);
221                avahi_threaded_poll_unlock(avahipoll);
222                return;
223        }
224
225        // tell the server to register the service
226        ret = avahi_entry_group_commit( currentgroup );
227        if(ret < 0) {
228                logging_warn("failed to commit entry group: " << avahi_strerror(ret));
229                avahigroups.erase(name);
230                avahi_threaded_poll_unlock(avahipoll);
231                return;
232        }
233
234        avahi_threaded_poll_unlock(avahipoll);
235
236  #endif // HAVE_AVAHI_CLIENT_CLIENT_H
237}
238
239void MulticastDns::revokeService(string name){
240  #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
241
242        avahi_threaded_poll_lock(avahipoll);
243
244        AvahiGroupMap::iterator i = avahigroups.find(name);
245        if( i != avahigroups.end() ){
246
247                logging_debug("revoking service " << name);
248                avahi_entry_group_reset( i->second );
249
250        } else {
251                logging_warn("service " << name << " is not registered, cannot revoke");
252        }
253
254        avahi_threaded_poll_unlock(avahipoll);
255
256  #endif // HAVE_AVAHI_CLIENT_CLIENT_H
257}
258
259#ifdef HAVE_AVAHI_CLIENT_CLIENT_H
260
261void MulticastDns::client_callback(AvahiClient* client, AvahiClientState state, void* userdata){
262
263        MulticastDns* obj = (MulticastDns*)userdata;
264        assert( obj != NULL );
265
266    switch (state) {
267        case AVAHI_CLIENT_S_RUNNING:
268
269                // server has startup successfully and registered its host
270            // name on the network, so it's time to create our services
271
272                logging_debug("avahi client is running");
273            break;
274
275        case AVAHI_CLIENT_FAILURE:
276
277                logging_warn( "avahi client failure "
278                                << avahi_strerror(avahi_client_errno(client)) << ". quitting" );
279            avahi_threaded_poll_quit(obj->avahipoll);
280
281            break;
282
283        case AVAHI_CLIENT_S_COLLISION:
284
285                logging_warn("avahi client collision");
286                break;
287
288        case AVAHI_CLIENT_S_REGISTERING:
289
290            logging_debug("avahi client registering");
291            break;
292
293        case AVAHI_CLIENT_CONNECTING:
294
295                logging_debug("avahi client conencting");
296            break;
297    }
298}
299
300void MulticastDns::entry_group_callback(AvahiEntryGroup* group, AvahiEntryGroupState state, void* userdata){
301
302        AvahiClient* client = avahi_entry_group_get_client( group );
303        assert( client != NULL);
304
305        MulticastDns* obj = (MulticastDns*)userdata;
306        assert(obj != NULL);
307
308        //
309        // called whenever the entry group state changes
310        //
311
312        switch(state) {
313                case AVAHI_ENTRY_GROUP_ESTABLISHED:
314
315                        logging_debug( "service entry group successfully established" );
316                        break;
317
318                case AVAHI_ENTRY_GROUP_COLLISION:
319
320                        logging_warn("service name collision for name");
321                        break;
322
323                case AVAHI_ENTRY_GROUP_FAILURE:
324
325                        logging_warn("service group failure: " << avahi_strerror(avahi_client_errno(client)));
326                        avahi_threaded_poll_quit(obj->avahipoll);
327
328                        break;
329
330                case AVAHI_ENTRY_GROUP_UNCOMMITED:
331
332                        logging_debug("avahi entry group uncommited");
333                        break;
334
335                case AVAHI_ENTRY_GROUP_REGISTERING:
336
337                        logging_debug("avahi entry group registering");
338                        break;
339
340        } //switch(state)
341}
342
343void MulticastDns::browse_callback(AvahiServiceBrowser* browser, AvahiIfIndex interface,
344                AvahiProtocol protocol, AvahiBrowserEvent event, const char* name,
345                const char* type, const char* domain, AvahiLookupResultFlags flags, void* userdata){
346
347        AvahiClient* client = avahi_service_browser_get_client(browser);
348        MulticastDns* obj = (MulticastDns*)userdata;
349
350        assert( client != NULL);
351        assert( obj != NULL );
352
353        switch (event) {
354                case AVAHI_BROWSER_FAILURE:
355
356                        logging_warn("avahi browser failure " << avahi_strerror(avahi_client_errno(client)));
357                        avahi_threaded_poll_quit( obj->avahipoll );
358
359                        break;
360
361                case AVAHI_BROWSER_NEW:
362
363                        if (!(avahi_service_resolver_new(client,
364                                        interface, protocol, name, type, domain,
365                                        AVAHI_PROTO_UNSPEC, (AvahiLookupFlags)0,
366                                        MulticastDns::resolve_callback, obj))){
367                                logging_warn( "failed to resolve service " << name
368                                                << ", error " << avahi_strerror(avahi_client_errno(client)));
369                        }
370
371                        break;
372
373                case AVAHI_BROWSER_REMOVE:
374
375                        logging_debug("avahi browser remove");
376                        break;
377
378                case AVAHI_BROWSER_ALL_FOR_NOW:
379
380                        logging_debug("avahi all for now");
381                        break;
382
383                case AVAHI_BROWSER_CACHE_EXHAUSTED:
384
385                        logging_debug("avahi browser cache exhausted");
386                        break;
387        }
388}
389
390void MulticastDns::resolve_callback(AvahiServiceResolver* resolver, AvahiIfIndex interface,
391                AvahiProtocol protocol, AvahiResolverEvent event, const char *name,
392                const char* type, const char* domain, const char* host_name,
393                const AvahiAddress* address, uint16_t port, AvahiStringList* txt,
394                AvahiLookupResultFlags flags, void* userdata){
395
396        AvahiClient* client = avahi_service_resolver_get_client(resolver);
397        MulticastDns* obj = (MulticastDns*)userdata;
398
399        assert( client != NULL );
400        assert( obj  != NULL );
401
402        switch(event) {
403                case AVAHI_RESOLVER_FAILURE:
404
405                        logging_warn("resolver failed to resolve service " << name
406                                        << ", error " << avahi_strerror(avahi_client_errno(client)));
407                        break;
408
409                case AVAHI_RESOLVER_FOUND:
410
411                        string info1 = "";
412                        string info2 = "";
413                        string info3 = "";
414
415                        if(txt != NULL){
416                                char* cinfo = (char*)avahi_string_list_get_text(txt);
417                                info1 = string(cinfo);
418                                txt = avahi_string_list_get_next(txt);
419                        }
420
421                        if(txt != NULL){
422                                char* cinfo = (char*)avahi_string_list_get_text(txt);
423                                info2 = string(cinfo);
424                                txt = avahi_string_list_get_next(txt);
425                        }
426
427                        if(txt != NULL){
428                                char* cinfo = (char*)avahi_string_list_get_text(txt);
429                                info3 = string(cinfo);
430                                txt = avahi_string_list_get_next(txt);
431                        }
432
433                        if(obj != NULL && obj->callback != NULL)
434                                obj->callback->onBootstrapServiceFound(name, info1, info2, info3);
435
436                        break;
437        }
438
439        avahi_service_resolver_free( resolver );
440}
441
442#endif // HAVE_AVAHI_CLIENT_CLIENT_H
443
444}} //namespace ariba, utility
Note: See TracBrowser for help on using the repository browser.