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

Last change on this file since 4836 was 4836, checked in by Christoph Mayer, 15 years ago

einige avahi fixes und ablauf

File size: 11.8 KB
RevLine 
[4733]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
[4758]44const string MulticastDns::serviceType = "_spovnet._tcp";
[4733]45use_logging_cpp(MulticastDns);
46
[4758]47MulticastDns::MulticastDns(BootstrapInformationCallback* _callback) : BootstrapModule(_callback) {
[4836]48 #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
[4733]49 avahiclient = NULL;
50 avahipoll = NULL;
51 avahibrowser = NULL;
[4836]52 #endif // HAVE_AVAHI_CLIENT_CLIENT_H
[4733]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(){
[4836]67 #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
[4733]68 return true;
69 #else
70 return false;
71 #endif
72}
73
74void MulticastDns::start(){
[4836]75 #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
[4733]76
77 int error = 0;
78
79 // create a new avahi polling thread
80 avahipoll = avahi_threaded_poll_new();
[4758]81 if( avahipoll == NULL){
82 logging_error("creating avahi poll failed");
83 return;
84 }
[4733]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 );
[4758]89 if( avahiclient == NULL){
90 logging_error("creating avahi client failed");
91 return;
92 }
[4733]93
94 // block the event loop
95 avahi_threaded_poll_lock( avahipoll );
96
[4758]97 // create the service browser for the specified type
[4733]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
[4758]103 if( avahibrowser == NULL){
104 logging_error("creating avahi browser failed");
105 return;
106 }
107
[4733]108 //unblock the event loop and let it run
109 avahi_threaded_poll_unlock( avahipoll );
110 avahi_threaded_poll_start( avahipoll );
111
[4836]112 #endif // HAVE_AVAHI_CLIENT_CLIENT_H
[4733]113}
114
115void MulticastDns::stop(){
[4836]116 #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
[4733]117
[4758]118 //
119 // stop poll and free browser
120 //
121
[4733]122 avahi_threaded_poll_stop( avahipoll );
123 avahi_service_browser_free( avahibrowser );
[4758]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
[4733]140 avahi_client_free( avahiclient );
[4758]141 avahiclient = NULL;
142
[4733]143 avahi_threaded_poll_free( avahipoll );
[4758]144 avahipoll = NULL;
[4733]145
[4836]146 #endif // HAVE_AVAHI_CLIENT_CLIENT_H
[4733]147}
148
[4836]149void MulticastDns::publishService(string name, string info1, string info2, string info3){
150 #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
[4733]151
[4758]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
[4733]159 avahi_threaded_poll_lock(avahipoll);
160 assert( avahiclient != NULL );
161
162 int ret = 0;
163
[4758]164 //
165 // if we have no group for this service, create one
166 //
[4733]167
[4758]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);
[4733]180 return;
181 }
[4758]182
183 avahigroups.insert( make_pair(name, currentgroup) );
[4733]184 }
185
[4758]186 assert( currentgroup != NULL );
[4733]187
[4758]188 logging_debug("avahi adding service " << name << " to new group");
189
[4733]190 ret = avahi_entry_group_add_service(
[4758]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
[4836]200 info1.c_str(), // arbitrary info
201 info2.c_str(), // arbitrary info
202 info3.c_str(), // arbitrary info
[4758]203 NULL); // make that this is the last info field
[4733]204
205 if( ret < 0 ){
206 logging_warn("failed to add service " << name << ": " << avahi_strerror(ret));
[4758]207 avahigroups.erase(name);
208 avahi_threaded_poll_unlock(avahipoll);
[4733]209 return;
210 }
211
212 // tell the server to register the service
[4758]213 ret = avahi_entry_group_commit( currentgroup );
[4733]214 if(ret < 0) {
215 logging_warn("failed to commit entry group: " << avahi_strerror(ret));
[4758]216 avahigroups.erase(name);
217 avahi_threaded_poll_unlock(avahipoll);
218 return;
[4733]219 }
220
221 avahi_threaded_poll_unlock(avahipoll);
222
[4836]223 #endif // HAVE_AVAHI_CLIENT_CLIENT_H
[4733]224}
225
226void MulticastDns::revokeService(string name){
[4836]227 #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
[4733]228
[4758]229 avahi_threaded_poll_lock(avahipoll);
[4733]230
[4758]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
[4836]243 #endif // HAVE_AVAHI_CLIENT_CLIENT_H
[4733]244}
245
[4836]246#ifdef HAVE_AVAHI_CLIENT_CLIENT_H
[4733]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
[4758]264 logging_warn( "avahi client failure "
265 << avahi_strerror(avahi_client_errno(client)) << ". quitting" );
[4733]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
[4758]277 logging_debug("avahi client registering");
[4733]278 break;
279
280 case AVAHI_CLIENT_CONNECTING:
[4758]281
282 logging_debug("avahi client conencting");
[4733]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:
[4758]318
319 logging_debug("avahi entry group uncommited");
[4733]320 break;
321
322 case AVAHI_ENTRY_GROUP_REGISTERING:
[4758]323
324 logging_debug("avahi entry group registering");
[4733]325 break;
[4758]326
[4733]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))){
[4758]354 logging_warn( "failed to resolve service " << name
355 << ", error " << avahi_strerror(avahi_client_errno(client)));
[4733]356 }
357
358 break;
359
360 case AVAHI_BROWSER_REMOVE:
[4758]361
362 logging_debug("avahi browser remove");
[4733]363 break;
364
365 case AVAHI_BROWSER_ALL_FOR_NOW:
[4758]366
367 logging_debug("avahi all for now");
[4733]368 break;
369
370 case AVAHI_BROWSER_CACHE_EXHAUSTED:
[4758]371
372 logging_debug("avahi browser cache exhausted");
[4733]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
[4758]392 logging_warn("resolver failed to resolve service " << name
393 << ", error " << avahi_strerror(avahi_client_errno(client)));
[4733]394 break;
395
[4758]396 case AVAHI_RESOLVER_FOUND:
[4733]397
[4758]398 char addr[AVAHI_ADDRESS_STR_MAX];
[4733]399
[4758]400 avahi_address_snprint(addr, sizeof(addr), address);
[4733]401
[4836]402 string info1 = "";
403 string info2 = "";
404 string info3 = "";
405
406 if(txt != NULL){
407 char* cinfo = avahi_string_list_to_string(txt);
408 info1 = cinfo;
409 avahi_free(cinfo);
410 }
411
412 if(txt != NULL && avahi_string_list_get_next(txt) != NULL){
413 char* cinfo = avahi_string_list_to_string( avahi_string_list_get_next(txt) );
414 info2 = cinfo;
415 avahi_free(cinfo);
416 }
417
418 if(txt != NULL && avahi_string_list_get_next(txt) != NULL){
419 char* cinfo = avahi_string_list_to_string( avahi_string_list_get_next(txt) );
420 info3 = cinfo;
421 avahi_free(cinfo);
422 }
423
[4758]424 if(obj != NULL && obj->callback != NULL)
[4836]425 obj->callback->onBootstrapServiceFound(name, info1, info2, info3);
[4733]426
427 break;
428 }
429
430 avahi_service_resolver_free( resolver );
431}
432
[4836]433#endif // HAVE_AVAHI_CLIENT_CLIENT_H
[4733]434
435}} //namespace ariba, utility
Note: See TracBrowser for help on using the repository browser.