An Overlay-based
Virtual Network Substrate
SpoVNet

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

Last change on this file since 6841 was 5284, checked in by mies, 15 years ago

+ added new transport modules and adapted ariba to them
+ exchange endpoint descriptors an link establishment
+ clean up of base communication
+ link establishment with in the presence of multiple endpoints
+ local discovery for ipv6, ipv4 and bluetooth mac addresses

File size: 11.8 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) : BootstrapModule(_callback) {
49  #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
50        avahiclient = NULL;
51        avahipoll = NULL;
52        avahibrowser = NULL;
53  #endif // HAVE_AVAHI_CLIENT_CLIENT_H
54}
55
56MulticastDns::~MulticastDns(){
57}
58
59string MulticastDns::getName(){
60        return "MulticastDns";
61}
62
63string MulticastDns::getInformation(){
64        return "bootstrap module based on multicast-dns using the avahi library";
65}
66
67bool MulticastDns::isFunctional(){
68  #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
69        return true;
70  #else
71        return false;
72  #endif
73}
74
75void MulticastDns::start(){
76  #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
77
78        int error = 0;
79
80        // create a new avahi polling thread
81        avahipoll = avahi_threaded_poll_new();
82        if( avahipoll == NULL){
83                logging_error("creating avahi poll failed");
84                return;
85        }
86
87        // create a new avahi client
88        avahiclient = avahi_client_new(
89                        avahi_threaded_poll_get(avahipoll),
90                        (AvahiClientFlags)0,
91                        MulticastDns::client_callback,
92                        this,
93                        &error
94                        );
95
96        if( avahiclient == NULL){
97                logging_error("creating avahi client failed with error "<<
98                                error << ". make sure that the avahi-daemon is running. e.g. by installing avahi-utils");
99                return;
100        }
101
102        // block the event loop
103        avahi_threaded_poll_lock( avahipoll );
104
105        // create the service browser for the specified type
106        avahibrowser = avahi_service_browser_new(
107                        avahiclient, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
108                        serviceType.c_str(), NULL,
109                        (AvahiLookupFlags)0, MulticastDns::browse_callback, this);
110
111        if( avahibrowser == NULL){
112                logging_error("creating avahi browser failed");
113                return;
114        }
115
116        //unblock the event loop and let it run
117        avahi_threaded_poll_unlock( avahipoll );
118        avahi_threaded_poll_start( avahipoll );
119
120  #endif // HAVE_AVAHI_CLIENT_CLIENT_H
121}
122
123void MulticastDns::stop(){
124  #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
125
126        //
127        // stop poll and free browser
128        //
129
130        avahi_threaded_poll_stop( avahipoll );
131        avahi_service_browser_free( avahibrowser );
132        avahibrowser = NULL;
133
134        //
135        // free all registered groups
136        //
137
138        AvahiGroupMap::iterator i = avahigroups.begin();
139        AvahiGroupMap::iterator iend = avahigroups.end();
140
141        for( ; i != iend; i++)
142                avahi_entry_group_free( i->second );
143
144        //
145        // free client and poll
146        //
147
148        if(avahiclient != NULL)
149                avahi_client_free( avahiclient );
150        avahiclient = NULL;
151
152        if(avahipoll != NULL)
153                avahi_threaded_poll_free( avahipoll );
154        avahipoll = NULL;
155
156  #endif // HAVE_AVAHI_CLIENT_CLIENT_H
157}
158
159void MulticastDns::publishService(string name, string info1, string info2, string info3){
160  #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
161
162        if(name.length() > 63){
163                logging_error("service name length must not exceed 63 characters. "
164                                << name << " is " << name.length() << " characters");
165                return;
166        }
167
168        if( avahiclient == NULL ){
169                logging_error("avahi client is invalid");
170                return;
171        }
172
173        avahi_threaded_poll_lock(avahipoll);
174        int ret = 0;
175
176        //
177        // if we have no group for this service, create one
178        //
179
180        AvahiGroupMap::iterator igroup = avahigroups.find(name);
181        AvahiEntryGroup* currentgroup = (igroup != avahigroups.end() ? igroup->second : NULL);
182
183        if( currentgroup == NULL ){
184
185                logging_debug("creating group for service " << name);
186                currentgroup = avahi_entry_group_new(avahiclient, MulticastDns::entry_group_callback, this);
187
188                if(currentgroup == NULL){
189                        logging_error("failed creating avahi group for service "
190                                        << name << ": " << avahi_strerror(avahi_client_errno(avahiclient)));
191                        avahi_threaded_poll_unlock(avahipoll);
192                        return;
193                }
194
195                avahigroups.insert( make_pair(name, currentgroup) );
196        }
197
198        assert( currentgroup != NULL );
199
200        logging_debug("avahi adding service " << name << " to new group");
201
202        ret = avahi_entry_group_add_service(
203                        currentgroup,                   // group to add service to
204                        AVAHI_IF_UNSPEC,                // interface to announce, we use all interfaces
205                        AVAHI_PROTO_UNSPEC,     // protocol to announce, we use all protocols
206                        (AvahiPublishFlags)0,   // no special flags
207                        name.c_str(),                   // name of the service, no more than 63 characters
208                        serviceType.c_str(),    // type of the service: _spovnet._tcp (tcp does not mean anything here, just have to stick with this structure
209                        NULL,                                   // publish in all domains
210                        NULL,                                   // host name of our machine, let avahi find out
211                        3333,                                   // port number the service is on, just dummy, everything is encoded in TXT
212                        info1.c_str(),                  // arbitrary info
213                        info2.c_str(),                  // arbitrary info
214                        info3.c_str(),                  // arbitrary info
215                        NULL);                                  // make that this is the last info field
216
217        if( ret < 0 ){
218                logging_warn("failed to add service " << name << ": " << avahi_strerror(ret));
219                avahigroups.erase(name);
220                avahi_threaded_poll_unlock(avahipoll);
221                return;
222        }
223
224        // tell the server to register the service
225        ret = avahi_entry_group_commit( currentgroup );
226        if(ret < 0) {
227                logging_warn("failed to commit entry group: " << avahi_strerror(ret));
228                avahigroups.erase(name);
229                avahi_threaded_poll_unlock(avahipoll);
230                return;
231        }
232
233        avahi_threaded_poll_unlock(avahipoll);
234
235  #endif // HAVE_AVAHI_CLIENT_CLIENT_H
236}
237
238void MulticastDns::revokeService(string name){
239  #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
240
241        avahi_threaded_poll_lock(avahipoll);
242
243        AvahiGroupMap::iterator i = avahigroups.find(name);
244        if( i != avahigroups.end() ){
245
246                logging_debug("revoking service " << name);
247                avahi_entry_group_reset( i->second );
248
249        } else {
250                logging_warn("service " << name << " is not registered, cannot revoke");
251        }
252
253        avahi_threaded_poll_unlock(avahipoll);
254
255  #endif // HAVE_AVAHI_CLIENT_CLIENT_H
256}
257
258#ifdef HAVE_AVAHI_CLIENT_CLIENT_H
259
260void MulticastDns::client_callback(AvahiClient* client, AvahiClientState state, void* userdata){
261
262        MulticastDns* obj = (MulticastDns*)userdata;
263        assert( obj != NULL );
264
265    switch (state) {
266        case AVAHI_CLIENT_S_RUNNING:
267
268                // server has startup successfully and registered its host
269            // name on the network, so it's time to create our services
270
271                logging_debug("avahi client is running");
272            break;
273
274        case AVAHI_CLIENT_FAILURE:
275
276                logging_warn( "avahi client failure "
277                                << avahi_strerror(avahi_client_errno(client)) << ". quitting" );
278            avahi_threaded_poll_quit(obj->avahipoll);
279
280            break;
281
282        case AVAHI_CLIENT_S_COLLISION:
283
284                logging_warn("avahi client collision");
285                break;
286
287        case AVAHI_CLIENT_S_REGISTERING:
288
289            logging_debug("avahi client registering");
290            break;
291
292        case AVAHI_CLIENT_CONNECTING:
293
294                logging_debug("avahi client conencting");
295            break;
296    }
297}
298
299void MulticastDns::entry_group_callback(AvahiEntryGroup* group, AvahiEntryGroupState state, void* userdata){
300
301        AvahiClient* client = avahi_entry_group_get_client( group );
302        assert( client != NULL);
303
304        MulticastDns* obj = (MulticastDns*)userdata;
305        assert(obj != NULL);
306
307        //
308        // called whenever the entry group state changes
309        //
310
311        switch(state) {
312                case AVAHI_ENTRY_GROUP_ESTABLISHED:
313
314                        logging_debug( "service entry group successfully established" );
315                        break;
316
317                case AVAHI_ENTRY_GROUP_COLLISION:
318
319                        logging_warn("service name collision for name");
320                        break;
321
322                case AVAHI_ENTRY_GROUP_FAILURE:
323
324                        logging_warn("service group failure: " << avahi_strerror(avahi_client_errno(client)));
325                        avahi_threaded_poll_quit(obj->avahipoll);
326
327                        break;
328
329                case AVAHI_ENTRY_GROUP_UNCOMMITED:
330
331                        logging_debug("avahi entry group uncommited");
332                        break;
333
334                case AVAHI_ENTRY_GROUP_REGISTERING:
335
336                        logging_debug("avahi entry group registering");
337                        break;
338
339        } //switch(state)
340}
341
342void MulticastDns::browse_callback(AvahiServiceBrowser* browser, AvahiIfIndex interface,
343                AvahiProtocol protocol, AvahiBrowserEvent event, const char* name,
344                const char* type, const char* domain, AvahiLookupResultFlags flags, void* userdata){
345
346        AvahiClient* client = avahi_service_browser_get_client(browser);
347        MulticastDns* obj = (MulticastDns*)userdata;
348
349        assert( client != NULL);
350        assert( obj != NULL );
351
352        switch (event) {
353                case AVAHI_BROWSER_FAILURE:
354
355                        logging_warn("avahi browser failure " << avahi_strerror(avahi_client_errno(client)));
356                        avahi_threaded_poll_quit( obj->avahipoll );
357
358                        break;
359
360                case AVAHI_BROWSER_NEW:
361
362                        if (!(avahi_service_resolver_new(client,
363                                        interface, protocol, name, type, domain,
364                                        AVAHI_PROTO_UNSPEC, (AvahiLookupFlags)0,
365                                        MulticastDns::resolve_callback, obj))){
366                                logging_warn( "failed to resolve service " << name
367                                                << ", error " << avahi_strerror(avahi_client_errno(client)));
368                        }
369
370                        break;
371
372                case AVAHI_BROWSER_REMOVE:
373
374                        logging_debug("avahi browser remove");
375                        break;
376
377                case AVAHI_BROWSER_ALL_FOR_NOW:
378
379                        logging_debug("avahi all for now");
380                        break;
381
382                case AVAHI_BROWSER_CACHE_EXHAUSTED:
383
384                        logging_debug("avahi browser cache exhausted");
385                        break;
386        }
387}
388
389void MulticastDns::resolve_callback(AvahiServiceResolver* resolver, AvahiIfIndex interface,
390                AvahiProtocol protocol, AvahiResolverEvent event, const char *name,
391                const char* type, const char* domain, const char* host_name,
392                const AvahiAddress* address, uint16_t port, AvahiStringList* txt,
393                AvahiLookupResultFlags flags, void* userdata){
394
395        AvahiClient* client = avahi_service_resolver_get_client(resolver);
396        MulticastDns* obj = (MulticastDns*)userdata;
397
398        assert( client != NULL );
399        assert( obj  != NULL );
400
401        switch(event) {
402                case AVAHI_RESOLVER_FAILURE:
403
404                        logging_warn("resolver failed to resolve service " << name
405                                        << ", error " << avahi_strerror(avahi_client_errno(client)));
406                        break;
407
408                case AVAHI_RESOLVER_FOUND:
409
410                        string info1 = "";
411                        string info2 = "";
412                        string info3 = "";
413
414                        if(txt != NULL){
415                                char* cinfo = (char*)avahi_string_list_get_text(txt);
416                                info1 = string(cinfo);
417                                txt = avahi_string_list_get_next(txt);
418                        }
419
420                        if(txt != NULL){
421                                char* cinfo = (char*)avahi_string_list_get_text(txt);
422                                info2 = string(cinfo);
423                                txt = avahi_string_list_get_next(txt);
424                        }
425
426                        if(txt != NULL){
427                                char* cinfo = (char*)avahi_string_list_get_text(txt);
428                                info3 = string(cinfo);
429                                txt = avahi_string_list_get_next(txt);
430                        }
431
432                        if(obj != NULL && obj->callback != NULL)
433                                obj->callback->onBootstrapServiceFound(name, info1, info2, info3);
434
435                        break;
436        }
437
438        avahi_service_resolver_free( resolver );
439}
440
441#endif // HAVE_AVAHI_CLIENT_CLIENT_H
442
443}} //namespace ariba, utility
Note: See TracBrowser for help on using the repository browser.