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

Last change on this file since 5945 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
RevLine 
[5284]1
[4733]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
[4758]45const string MulticastDns::serviceType = "_spovnet._tcp";
[4733]46use_logging_cpp(MulticastDns);
47
[4758]48MulticastDns::MulticastDns(BootstrapInformationCallback* _callback) : BootstrapModule(_callback) {
[4836]49 #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
[4733]50 avahiclient = NULL;
51 avahipoll = NULL;
52 avahibrowser = NULL;
[4836]53 #endif // HAVE_AVAHI_CLIENT_CLIENT_H
[4733]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(){
[4836]68 #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
[4733]69 return true;
70 #else
71 return false;
72 #endif
73}
74
75void MulticastDns::start(){
[4836]76 #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
[4733]77
78 int error = 0;
79
80 // create a new avahi polling thread
81 avahipoll = avahi_threaded_poll_new();
[4758]82 if( avahipoll == NULL){
83 logging_error("creating avahi poll failed");
84 return;
85 }
[4733]86
87 // create a new avahi client
[4850]88 avahiclient = avahi_client_new(
89 avahi_threaded_poll_get(avahipoll),
90 (AvahiClientFlags)0,
91 MulticastDns::client_callback,
92 this,
93 &error
94 );
95
[4758]96 if( avahiclient == NULL){
[4842]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");
[4758]99 return;
100 }
[4733]101
102 // block the event loop
103 avahi_threaded_poll_lock( avahipoll );
104
[4758]105 // create the service browser for the specified type
[4733]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
[4758]111 if( avahibrowser == NULL){
112 logging_error("creating avahi browser failed");
113 return;
114 }
115
[4733]116 //unblock the event loop and let it run
117 avahi_threaded_poll_unlock( avahipoll );
118 avahi_threaded_poll_start( avahipoll );
119
[4836]120 #endif // HAVE_AVAHI_CLIENT_CLIENT_H
[4733]121}
122
123void MulticastDns::stop(){
[4836]124 #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
[4733]125
[4758]126 //
127 // stop poll and free browser
128 //
129
[4733]130 avahi_threaded_poll_stop( avahipoll );
131 avahi_service_browser_free( avahibrowser );
[4758]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
[4841]148 if(avahiclient != NULL)
149 avahi_client_free( avahiclient );
[4758]150 avahiclient = NULL;
151
[4841]152 if(avahipoll != NULL)
153 avahi_threaded_poll_free( avahipoll );
[4758]154 avahipoll = NULL;
[4733]155
[4836]156 #endif // HAVE_AVAHI_CLIENT_CLIENT_H
[4733]157}
158
[4836]159void MulticastDns::publishService(string name, string info1, string info2, string info3){
160 #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
[4733]161
[4758]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
[4841]168 if( avahiclient == NULL ){
169 logging_error("avahi client is invalid");
170 return;
171 }
[4758]172
[4733]173 avahi_threaded_poll_lock(avahipoll);
174 int ret = 0;
175
[4758]176 //
177 // if we have no group for this service, create one
178 //
[4733]179
[4758]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);
[4733]192 return;
193 }
[4758]194
195 avahigroups.insert( make_pair(name, currentgroup) );
[4733]196 }
197
[4758]198 assert( currentgroup != NULL );
[4733]199
[4758]200 logging_debug("avahi adding service " << name << " to new group");
201
[4733]202 ret = avahi_entry_group_add_service(
[4758]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
[4836]212 info1.c_str(), // arbitrary info
213 info2.c_str(), // arbitrary info
214 info3.c_str(), // arbitrary info
[4758]215 NULL); // make that this is the last info field
[4733]216
217 if( ret < 0 ){
218 logging_warn("failed to add service " << name << ": " << avahi_strerror(ret));
[4758]219 avahigroups.erase(name);
220 avahi_threaded_poll_unlock(avahipoll);
[4733]221 return;
222 }
223
224 // tell the server to register the service
[4758]225 ret = avahi_entry_group_commit( currentgroup );
[4733]226 if(ret < 0) {
227 logging_warn("failed to commit entry group: " << avahi_strerror(ret));
[4758]228 avahigroups.erase(name);
229 avahi_threaded_poll_unlock(avahipoll);
230 return;
[4733]231 }
232
233 avahi_threaded_poll_unlock(avahipoll);
234
[4836]235 #endif // HAVE_AVAHI_CLIENT_CLIENT_H
[4733]236}
237
238void MulticastDns::revokeService(string name){
[4836]239 #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
[4733]240
[4758]241 avahi_threaded_poll_lock(avahipoll);
[4733]242
[4758]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
[4836]255 #endif // HAVE_AVAHI_CLIENT_CLIENT_H
[4733]256}
257
[4836]258#ifdef HAVE_AVAHI_CLIENT_CLIENT_H
[4733]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
[4758]276 logging_warn( "avahi client failure "
277 << avahi_strerror(avahi_client_errno(client)) << ". quitting" );
[4733]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
[4758]289 logging_debug("avahi client registering");
[4733]290 break;
291
292 case AVAHI_CLIENT_CONNECTING:
[4758]293
294 logging_debug("avahi client conencting");
[4733]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:
[4758]330
331 logging_debug("avahi entry group uncommited");
[4733]332 break;
333
334 case AVAHI_ENTRY_GROUP_REGISTERING:
[4758]335
336 logging_debug("avahi entry group registering");
[4733]337 break;
[4758]338
[4733]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))){
[4758]366 logging_warn( "failed to resolve service " << name
367 << ", error " << avahi_strerror(avahi_client_errno(client)));
[4733]368 }
369
370 break;
371
372 case AVAHI_BROWSER_REMOVE:
[4758]373
374 logging_debug("avahi browser remove");
[4733]375 break;
376
377 case AVAHI_BROWSER_ALL_FOR_NOW:
[4758]378
379 logging_debug("avahi all for now");
[4733]380 break;
381
382 case AVAHI_BROWSER_CACHE_EXHAUSTED:
[4758]383
384 logging_debug("avahi browser cache exhausted");
[4733]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
[4758]404 logging_warn("resolver failed to resolve service " << name
405 << ", error " << avahi_strerror(avahi_client_errno(client)));
[4733]406 break;
407
[4758]408 case AVAHI_RESOLVER_FOUND:
[4733]409
[4836]410 string info1 = "";
411 string info2 = "";
412 string info3 = "";
413
414 if(txt != NULL){
[4838]415 char* cinfo = (char*)avahi_string_list_get_text(txt);
416 info1 = string(cinfo);
417 txt = avahi_string_list_get_next(txt);
[4836]418 }
419
[4838]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);
[4836]424 }
425
[4838]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);
[4836]430 }
431
[4758]432 if(obj != NULL && obj->callback != NULL)
[4836]433 obj->callback->onBootstrapServiceFound(name, info1, info2, info3);
[4733]434
435 break;
436 }
437
438 avahi_service_resolver_free( resolver );
439}
440
[4836]441#endif // HAVE_AVAHI_CLIENT_CLIENT_H
[4733]442
443}} //namespace ariba, utility
Note: See TracBrowser for help on using the repository browser.