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