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

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

-neues bootstrap module für dumme periodische broadcasts

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