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