34 #include <semaphore.h>
36 #include <arpa/inet.h>
37 #include <sys/socket.h>
38 #include <netinet/in.h>
47 void entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, AVAHI_GCC_UNUSED
void *userdata) {
48 AvahiClient *client = avahi_entry_group_get_client(g);
51 assert(zConfigurator);
55 case AVAHI_ENTRY_GROUP_ESTABLISHED :
57 cerr <<
"Service " << zConfigurator->serviceName <<
" successfully established." << endl;
60 case AVAHI_ENTRY_GROUP_COLLISION : {
64 n = avahi_alternative_service_name(zConfigurator->serviceName);
65 avahi_free(zConfigurator->serviceName);
66 zConfigurator->serviceName = n;
68 cerr <<
"Service name collision, renaming service to " << n <<
"." << endl;
71 create_services(client, zConfigurator);
75 case AVAHI_ENTRY_GROUP_FAILURE :
77 cerr <<
"Entry group failure: " << avahi_strerror(avahi_client_errno(client)) << endl;
79 avahi_threaded_poll_quit(zConfigurator->threadedPoll);
93 assert(zConfigurator);
96 cerr <<
"ZeroconfConnector not available, can not create service" << endl;
104 if (!zConfigurator->group)
105 if (!(zConfigurator->group = avahi_entry_group_new(c, entry_group_callback, zConfigurator))) {
106 cerr <<
"avahi_entry_group_new() failed: " << avahi_strerror(avahi_client_errno(c)) << endl;
114 if (avahi_entry_group_is_empty(zConfigurator->group)) {
115 cerr <<
"Adding service " << zConfigurator->serviceName << endl;
117 snprintf(r[0],
sizeof(r[0]),
"peerid=%s", (zConfigurator->thisNode->key.toString(16)).c_str());
118 snprintf(r[1],
sizeof(r[1]),
"overlayid=%s", zConfigurator->overlayName);
119 snprintf(r[2],
sizeof(r[2]),
"overlaytype=%s", zConfigurator->overlayType);
122 if ((ret = avahi_entry_group_add_service(zConfigurator->group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,(AvahiPublishFlags)0,
123 zConfigurator->serviceName, zConfigurator->serviceType, NULL, NULL, zConfigurator->thisNode->getPort(), r[0], r[1], r[2], NULL)) < 0) {
125 if (ret == AVAHI_ERR_COLLISION)
128 cerr <<
"Failed to add _p2pbootstrap._udp service: " << avahi_strerror(ret) << endl;
133 if ((ret = avahi_entry_group_commit(zConfigurator->group)) < 0) {
134 cerr <<
"Failed to commit entry group: " << avahi_strerror(ret) << endl;
145 n = avahi_alternative_service_name(zConfigurator->serviceName);
146 avahi_free(zConfigurator->serviceName);
147 zConfigurator->serviceName = n;
149 cerr <<
"Service name collision, renaming service to " << n << endl;
151 avahi_entry_group_reset(zConfigurator->group);
153 create_services(c, zConfigurator);
157 avahi_threaded_poll_quit(zConfigurator->threadedPoll);
160 void resolv_callback(
161 AvahiServiceResolver *r,
162 AVAHI_GCC_UNUSED AvahiIfIndex interface,
163 AVAHI_GCC_UNUSED AvahiProtocol protocol,
164 AvahiResolverEvent event,
168 const char *host_name,
169 const AvahiAddress *address,
171 AvahiStringList *txt,
172 AvahiLookupResultFlags flags,
173 AVAHI_GCC_UNUSED
void* userdata) {
176 char *overlayType = NULL;
177 AvahiStringList *record;
178 AvahiClient *client = NULL;
183 client = avahi_service_resolver_get_client(r);
187 assert(zConfigurator);
192 case AVAHI_RESOLVER_FAILURE:
193 cerr <<
"(Resolver) Failed to resolve service " << name <<
" of type " << type <<
" in domain " <<
194 domain <<
": " << avahi_strerror(avahi_client_errno(client)) << endl;
197 case AVAHI_RESOLVER_FOUND: {
198 char a[AVAHI_ADDRESS_STR_MAX], *t;
200 cout <<
"Service " << name <<
" of type " << type <<
" in domain " << domain << endl;
202 avahi_address_snprint(a,
sizeof(a), address);
203 t = avahi_string_list_to_string(txt);
215 avahi_string_list_get_service_cookie(txt),
216 !!(flags & AVAHI_LOOKUP_RESULT_LOCAL),
217 !!(flags & AVAHI_LOOKUP_RESULT_OUR_OWN),
218 !!(flags & AVAHI_LOOKUP_RESULT_WIDE_AREA),
219 !!(flags & AVAHI_LOOKUP_RESULT_MULTICAST),
220 !!(flags & AVAHI_LOOKUP_RESULT_CACHED));
225 for (record = txt; record; record = record->next) {
226 if (!strncmp((
char *)record->text,
"overlaytype", 11)) {
227 if ((
char)record->text[11] ==
'=') {
228 overlayType = avahi_strdup((
const char *)(record->text + 12));
231 if (!strncmp((
char *)record->text,
"peerid", 6)) {
232 if (record->text[6] ==
'=') {
233 peerID = avahi_strdup((
const char *)(record->text + 7));
239 if (!overlayType || !peerID || strncmp(overlayType, zConfigurator->overlayType,
240 strlen(overlayType))) {
241 cerr <<
"TXT record of the node is defect, or node does not use the desired p2p algorithm." << endl;
244 avahi_free(overlayType);
254 IPvXAddress(a), (
int)port,
255 !!(flags & AVAHI_LOOKUP_RESULT_WIDE_AREA) ?
DNSSD :
MDNS);
258 zConfigurator->insertNode(avahi_strdup(name), node);
260 cerr <<
"Failed to allocate memory for NodeHandle" << endl;
264 avahi_free(overlayType);
274 avahi_service_resolver_free(r);
279 void browse_callback(
280 AvahiServiceBrowser *b,
281 AvahiIfIndex interface,
282 AvahiProtocol protocol,
283 AvahiBrowserEvent event,
287 AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
290 AvahiClient *c = NULL;
294 c = avahi_service_browser_get_client(b);
298 assert(zConfigurator);
302 case AVAHI_BROWSER_FAILURE:
303 cerr <<
"(Browser) " << avahi_strerror(avahi_client_errno(c)) << endl;
304 avahi_threaded_poll_quit(zConfigurator->threadedPoll);
307 case AVAHI_BROWSER_NEW:
308 cerr <<
"(Browser) NEW: service " << name <<
" of type " << type <<
" in domain " << domain << endl;
310 if (strcmp(name, zConfigurator->serviceName)) {
311 if (!(avahi_service_resolver_new(c, interface, protocol, name, type, domain, AVAHI_PROTO_INET, (AvahiLookupFlags)0, resolv_callback, zConfigurator)))
312 cerr <<
"Failed to resolve service " << name <<
":" << avahi_strerror(avahi_client_errno(c)) << endl;
316 case AVAHI_BROWSER_REMOVE:
317 cerr <<
"(Browser) REMOVE: service " << name <<
" of type " << type <<
" in domain " << domain << endl;
318 zConfigurator->removeNode((
char *)name);
321 case AVAHI_BROWSER_ALL_FOR_NOW:
322 case AVAHI_BROWSER_CACHE_EXHAUSTED:
323 cerr <<
"(Browser) " << (
event == AVAHI_BROWSER_CACHE_EXHAUSTED ?
"CACHE_EXHAUSTED" :
"ALL_FOR_NOW") << endl;
332 void client_callback(
334 AvahiClientState state,
335 AVAHI_GCC_UNUSED
void * userdata) {
340 assert(zConfigurator);
344 case AVAHI_CLIENT_FAILURE:
345 cerr <<
"Client failure: " << avahi_strerror(avahi_client_errno(c)) << endl;
346 avahi_threaded_poll_quit(zConfigurator->threadedPoll);
350 case AVAHI_CLIENT_S_REGISTERING:
351 if (zConfigurator->group)
352 avahi_entry_group_reset(zConfigurator->group);
364 initResult = AVAHI_INIT_FAILED;
370 sbMDNS = sbUDNS = NULL;
372 serviceType = overlayName = overlayType = NULL;
376 if (sem_init(&nodeSetSem, 0, 1) == -1) {
377 cerr <<
"nodeSetSem can't be initialized." << endl;
392 LocalBNodeSet::iterator iter;
393 cancelAndDelete(pollingTimer);
395 avahi_threaded_poll_stop(threadedPoll);
396 avahi_service_browser_free(sbMDNS);
397 avahi_service_browser_free(sbUDNS);
400 avahi_entry_group_free(group);
402 avahi_client_free(client);
403 avahi_threaded_poll_free(threadedPoll);
405 sem_destroy(&nodeSetSem);
407 for (iter = newSet.begin(); iter != newSet.end(); iter++) {
408 avahi_free(iter->first);
414 avahi_free(serviceName);
426 cerr <<
"unspecified node for service announcement" << endl;
431 cerr <<
"no resource to save local node" << endl;
435 create_services(client,
this);
447 avahi_entry_group_reset(group);
456 cerr <<
"Trying to insert invalid node" << endl;
460 cerr <<
"insertNode called" << endl;
462 sem_wait(&nodeSetSem);
463 newSet.insert(LocalNodePair(name, node));
465 sem_post(&nodeSetSem);
471 int ZeroconfConnector::removeNode(
char *name)
473 LocalBNodeSet::iterator iter;
475 cerr <<
"node name invalid" << endl;
479 sem_wait(&nodeSetSem);
481 iter = newSet.find((
char *)name);
482 if (iter != newSet.end()) {
484 avahi_free(iter->first);
488 sem_post(&nodeSetSem);
493 inline int ZeroconfConnector::getInitResult()
499 void ZeroconfConnector::initialize()
503 enabled = par(
"enableZeroconf");
504 serviceType = par(
"serviceType");
505 serviceName = avahi_strdup(par(
"serviceName"));
506 overlayType = par(
"overlayType");
507 overlayName = par(
"overlayName");
513 if (!(threadedPoll = avahi_threaded_poll_new())) {
514 cerr <<
"Failed to create a threaded poll." << endl;
519 if (!(client = avahi_client_new(avahi_threaded_poll_get(threadedPoll), (AvahiClientFlags)0, client_callback,
521 cerr <<
"Failed to create a client." << endl;
526 if (!(sbMDNS = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_INET, serviceType, NULL,
527 (AvahiLookupFlags)0, browse_callback,
this))) {
528 cerr <<
"Failed to create a service browser." << endl;
532 if (!(sbUDNS = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_INET, serviceType, overlayName,
533 (AvahiLookupFlags)0, browse_callback,
this))) {
534 cerr <<
"Failed to create a service browser." << endl;
538 if (avahi_threaded_poll_start(threadedPoll) < 0) {
539 cerr <<
"Failed to start the threaded poll." << endl;
543 pollingTimer =
new cMessage(
"Zeroconf timer");
545 scheduleAt(simTime() + 1, pollingTimer);
546 initResult = AVAHI_INIT_SUCCEEDED;
552 avahi_service_browser_free(sbMDNS);
555 avahi_service_browser_free(sbUDNS);
558 avahi_client_free(client);
561 avahi_threaded_poll_free(threadedPoll);
569 void ZeroconfConnector::handleMessage(cMessage *msg)
573 LocalBNodeSet::iterator tempIter;
576 check_and_cast<
BootstrapList *>(getParentModule()->getSubmodule(
"singleHost", 0)->getSubmodule(
"bootstrapList", 0));
578 if (msg->isSelfMessage()) {
579 if (!sem_trywait(&nodeSetSem)) {
580 if (!newSet.empty()) {
581 for (LocalBNodeSet::iterator iter = newSet.begin(); iter != newSet.end();) {
593 newSet.erase(tempIter);
600 sem_post(&nodeSetSem);
604 scheduleAt(simTime() + 5, msg);