00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #include "MulticastDns.h"
00041
00042 namespace ariba {
00043 namespace utility {
00044
00045 const string MulticastDns::serviceType = "_spovnet._tcp";
00046 use_logging_cpp(MulticastDns);
00047
00048 MulticastDns::MulticastDns(BootstrapInformationCallback* _callback) : BootstrapModule(_callback) {
00049 #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
00050 avahiclient = NULL;
00051 avahipoll = NULL;
00052 avahibrowser = NULL;
00053 #endif // HAVE_AVAHI_CLIENT_CLIENT_H
00054 }
00055
00056 MulticastDns::~MulticastDns(){
00057 }
00058
00059 string MulticastDns::getName(){
00060 return "MulticastDns";
00061 }
00062
00063 string MulticastDns::getInformation(){
00064 return "bootstrap module based on multicast-dns using the avahi library";
00065 }
00066
00067 bool MulticastDns::isFunctional(){
00068 #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
00069 return true;
00070 #else
00071 return false;
00072 #endif
00073 }
00074
00075 void MulticastDns::start(){
00076 #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
00077
00078 int error = 0;
00079
00080
00081 avahipoll = avahi_threaded_poll_new();
00082 if( avahipoll == NULL){
00083 logging_error("creating avahi poll failed");
00084 return;
00085 }
00086
00087
00088 avahiclient = avahi_client_new(
00089 avahi_threaded_poll_get(avahipoll),
00090 (AvahiClientFlags)0,
00091 MulticastDns::client_callback,
00092 this,
00093 &error
00094 );
00095
00096 if( avahiclient == NULL){
00097 logging_error("creating avahi client failed with error "<<
00098 error << ". make sure that the avahi-daemon is running. e.g. by installing avahi-utils");
00099 return;
00100 }
00101
00102
00103 avahi_threaded_poll_lock( avahipoll );
00104
00105
00106 avahibrowser = avahi_service_browser_new(
00107 avahiclient, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
00108 serviceType.c_str(), NULL,
00109 (AvahiLookupFlags)0, MulticastDns::browse_callback, this);
00110
00111 if( avahibrowser == NULL){
00112 logging_error("creating avahi browser failed");
00113 return;
00114 }
00115
00116
00117 avahi_threaded_poll_unlock( avahipoll );
00118 avahi_threaded_poll_start( avahipoll );
00119
00120 #endif // HAVE_AVAHI_CLIENT_CLIENT_H
00121 }
00122
00123 void MulticastDns::stop(){
00124 #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
00125
00126
00127
00128
00129
00130 avahi_threaded_poll_stop( avahipoll );
00131 avahi_service_browser_free( avahibrowser );
00132 avahibrowser = NULL;
00133
00134
00135
00136
00137
00138 AvahiGroupMap::iterator i = avahigroups.begin();
00139 AvahiGroupMap::iterator iend = avahigroups.end();
00140
00141 for( ; i != iend; i++)
00142 avahi_entry_group_free( i->second );
00143
00144
00145
00146
00147
00148 if(avahiclient != NULL)
00149 avahi_client_free( avahiclient );
00150 avahiclient = NULL;
00151
00152 if(avahipoll != NULL)
00153 avahi_threaded_poll_free( avahipoll );
00154 avahipoll = NULL;
00155
00156 #endif // HAVE_AVAHI_CLIENT_CLIENT_H
00157 }
00158
00159 void MulticastDns::publishService(string name, string info1, string info2, string info3){
00160 #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
00161
00162 if(name.length() > 63){
00163 logging_error("service name length must not exceed 63 characters. "
00164 << name << " is " << name.length() << " characters");
00165 return;
00166 }
00167
00168 if( avahiclient == NULL ){
00169 logging_error("avahi client is invalid");
00170 return;
00171 }
00172
00173 avahi_threaded_poll_lock(avahipoll);
00174 int ret = 0;
00175
00176
00177
00178
00179
00180 AvahiGroupMap::iterator igroup = avahigroups.find(name);
00181 AvahiEntryGroup* currentgroup = (igroup != avahigroups.end() ? igroup->second : NULL);
00182
00183 if( currentgroup == NULL ){
00184
00185 logging_debug("creating group for service " << name);
00186 currentgroup = avahi_entry_group_new(avahiclient, MulticastDns::entry_group_callback, this);
00187
00188 if(currentgroup == NULL){
00189 logging_error("failed creating avahi group for service "
00190 << name << ": " << avahi_strerror(avahi_client_errno(avahiclient)));
00191 avahi_threaded_poll_unlock(avahipoll);
00192 return;
00193 }
00194
00195 avahigroups.insert( make_pair(name, currentgroup) );
00196 }
00197
00198 assert( currentgroup != NULL );
00199
00200 logging_debug("avahi adding service " << name << " to new group");
00201
00202 ret = avahi_entry_group_add_service(
00203 currentgroup,
00204 AVAHI_IF_UNSPEC,
00205 AVAHI_PROTO_UNSPEC,
00206 (AvahiPublishFlags)0,
00207 name.c_str(),
00208 serviceType.c_str(),
00209 NULL,
00210 NULL,
00211 3333,
00212 info1.c_str(),
00213 info2.c_str(),
00214 info3.c_str(),
00215 NULL);
00216
00217 if( ret < 0 ){
00218 logging_warn("failed to add service " << name << ": " << avahi_strerror(ret));
00219 avahigroups.erase(name);
00220 avahi_threaded_poll_unlock(avahipoll);
00221 return;
00222 }
00223
00224
00225 ret = avahi_entry_group_commit( currentgroup );
00226 if(ret < 0) {
00227 logging_warn("failed to commit entry group: " << avahi_strerror(ret));
00228 avahigroups.erase(name);
00229 avahi_threaded_poll_unlock(avahipoll);
00230 return;
00231 }
00232
00233 avahi_threaded_poll_unlock(avahipoll);
00234
00235 #endif // HAVE_AVAHI_CLIENT_CLIENT_H
00236 }
00237
00238 void MulticastDns::revokeService(string name){
00239 #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
00240
00241 avahi_threaded_poll_lock(avahipoll);
00242
00243 AvahiGroupMap::iterator i = avahigroups.find(name);
00244 if( i != avahigroups.end() ){
00245
00246 logging_debug("revoking service " << name);
00247 avahi_entry_group_reset( i->second );
00248
00249 } else {
00250 logging_warn("service " << name << " is not registered, cannot revoke");
00251 }
00252
00253 avahi_threaded_poll_unlock(avahipoll);
00254
00255 #endif // HAVE_AVAHI_CLIENT_CLIENT_H
00256 }
00257
00258 #ifdef HAVE_AVAHI_CLIENT_CLIENT_H
00259
00260 void MulticastDns::client_callback(AvahiClient* client, AvahiClientState state, void* userdata){
00261
00262 MulticastDns* obj = (MulticastDns*)userdata;
00263 assert( obj != NULL );
00264
00265 switch (state) {
00266 case AVAHI_CLIENT_S_RUNNING:
00267
00268
00269
00270
00271 logging_debug("avahi client is running");
00272 break;
00273
00274 case AVAHI_CLIENT_FAILURE:
00275
00276 logging_warn( "avahi client failure "
00277 << avahi_strerror(avahi_client_errno(client)) << ". quitting" );
00278 avahi_threaded_poll_quit(obj->avahipoll);
00279
00280 break;
00281
00282 case AVAHI_CLIENT_S_COLLISION:
00283
00284 logging_warn("avahi client collision");
00285 break;
00286
00287 case AVAHI_CLIENT_S_REGISTERING:
00288
00289 logging_debug("avahi client registering");
00290 break;
00291
00292 case AVAHI_CLIENT_CONNECTING:
00293
00294 logging_debug("avahi client conencting");
00295 break;
00296 }
00297 }
00298
00299 void MulticastDns::entry_group_callback(AvahiEntryGroup* group, AvahiEntryGroupState state, void* userdata){
00300
00301 AvahiClient* client = avahi_entry_group_get_client( group );
00302 assert( client != NULL);
00303
00304 MulticastDns* obj = (MulticastDns*)userdata;
00305 assert(obj != NULL);
00306
00307
00308
00309
00310
00311 switch(state) {
00312 case AVAHI_ENTRY_GROUP_ESTABLISHED:
00313
00314 logging_debug( "service entry group successfully established" );
00315 break;
00316
00317 case AVAHI_ENTRY_GROUP_COLLISION:
00318
00319 logging_warn("service name collision for name");
00320 break;
00321
00322 case AVAHI_ENTRY_GROUP_FAILURE:
00323
00324 logging_warn("service group failure: " << avahi_strerror(avahi_client_errno(client)));
00325 avahi_threaded_poll_quit(obj->avahipoll);
00326
00327 break;
00328
00329 case AVAHI_ENTRY_GROUP_UNCOMMITED:
00330
00331 logging_debug("avahi entry group uncommited");
00332 break;
00333
00334 case AVAHI_ENTRY_GROUP_REGISTERING:
00335
00336 logging_debug("avahi entry group registering");
00337 break;
00338
00339 }
00340 }
00341
00342 void MulticastDns::browse_callback(AvahiServiceBrowser* browser, AvahiIfIndex interface,
00343 AvahiProtocol protocol, AvahiBrowserEvent event, const char* name,
00344 const char* type, const char* domain, AvahiLookupResultFlags flags, void* userdata){
00345
00346 AvahiClient* client = avahi_service_browser_get_client(browser);
00347 MulticastDns* obj = (MulticastDns*)userdata;
00348
00349 assert( client != NULL);
00350 assert( obj != NULL );
00351
00352 switch (event) {
00353 case AVAHI_BROWSER_FAILURE:
00354
00355 logging_warn("avahi browser failure " << avahi_strerror(avahi_client_errno(client)));
00356 avahi_threaded_poll_quit( obj->avahipoll );
00357
00358 break;
00359
00360 case AVAHI_BROWSER_NEW:
00361
00362 if (!(avahi_service_resolver_new(client,
00363 interface, protocol, name, type, domain,
00364 AVAHI_PROTO_UNSPEC, (AvahiLookupFlags)0,
00365 MulticastDns::resolve_callback, obj))){
00366 logging_warn( "failed to resolve service " << name
00367 << ", error " << avahi_strerror(avahi_client_errno(client)));
00368 }
00369
00370 break;
00371
00372 case AVAHI_BROWSER_REMOVE:
00373
00374 logging_debug("avahi browser remove");
00375 break;
00376
00377 case AVAHI_BROWSER_ALL_FOR_NOW:
00378
00379 logging_debug("avahi all for now");
00380 break;
00381
00382 case AVAHI_BROWSER_CACHE_EXHAUSTED:
00383
00384 logging_debug("avahi browser cache exhausted");
00385 break;
00386 }
00387 }
00388
00389 void MulticastDns::resolve_callback(AvahiServiceResolver* resolver, AvahiIfIndex interface,
00390 AvahiProtocol protocol, AvahiResolverEvent event, const char *name,
00391 const char* type, const char* domain, const char* host_name,
00392 const AvahiAddress* address, uint16_t port, AvahiStringList* txt,
00393 AvahiLookupResultFlags flags, void* userdata){
00394
00395 AvahiClient* client = avahi_service_resolver_get_client(resolver);
00396 MulticastDns* obj = (MulticastDns*)userdata;
00397
00398 assert( client != NULL );
00399 assert( obj != NULL );
00400
00401 switch(event) {
00402 case AVAHI_RESOLVER_FAILURE:
00403
00404 logging_warn("resolver failed to resolve service " << name
00405 << ", error " << avahi_strerror(avahi_client_errno(client)));
00406 break;
00407
00408 case AVAHI_RESOLVER_FOUND:
00409
00410 string info1 = "";
00411 string info2 = "";
00412 string info3 = "";
00413
00414 if(txt != NULL){
00415 char* cinfo = (char*)avahi_string_list_get_text(txt);
00416 info1 = string(cinfo);
00417 txt = avahi_string_list_get_next(txt);
00418 }
00419
00420 if(txt != NULL){
00421 char* cinfo = (char*)avahi_string_list_get_text(txt);
00422 info2 = string(cinfo);
00423 txt = avahi_string_list_get_next(txt);
00424 }
00425
00426 if(txt != NULL){
00427 char* cinfo = (char*)avahi_string_list_get_text(txt);
00428 info3 = string(cinfo);
00429 txt = avahi_string_list_get_next(txt);
00430 }
00431
00432 if(obj != NULL && obj->callback != NULL)
00433 obj->callback->onBootstrapServiceFound(name, info1, info2, info3);
00434
00435 break;
00436 }
00437
00438 avahi_service_resolver_free( resolver );
00439 }
00440
00441 #endif // HAVE_AVAHI_CLIENT_CLIENT_H
00442
00443 }}