An Overlay-based
Virtual Network Substrate
SpoVNet

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

Last change on this file since 4838 was 4838, checked in by Christoph Mayer, 14 years ago

bootstrap ablauf fixes und avahi fixes

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