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

Last change on this file was 10700, checked in by Michael Tänzer, 12 years ago

Merge CMake branch into trunk

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