/* * This function tries to register the AFP DNS * SRV service type. */ static void register_stuff(void) { uint port; const struct vol *volume; DSI *dsi; char name[MAXINSTANCENAMELEN+1]; AvahiStringList *strlist = NULL; AvahiStringList *strlist2 = NULL; char tmpname[256]; assert(ctx->client); if (!ctx->group) { if (!(ctx->group = avahi_entry_group_new(ctx->client, publish_reply, ctx))) { LOG(log_error, logtype_afpd, "Failed to create entry group: %s", avahi_strerror(avahi_client_errno(ctx->client))); goto fail; } } if (avahi_entry_group_is_empty(ctx->group)) { /* Register our service */ /* Build AFP volumes list */ int i = 0; strlist = avahi_string_list_add_printf(strlist, "sys=waMa=0,adVF=0x100"); for (volume = getvolumes(); volume; volume = volume->v_next) { if (convert_string(CH_UCS2, CH_UTF8_MAC, volume->v_u8mname, -1, tmpname, 255) <= 0) { LOG ( log_error, logtype_afpd, "Could not set Zeroconf volume name for TimeMachine"); goto fail; } if (volume->v_flags & AFPVOL_TM) { if (volume->v_uuid) { LOG(log_info, logtype_afpd, "Registering volume '%s' with UUID: '%s' for TimeMachine", volume->v_localname, volume->v_uuid); strlist = avahi_string_list_add_printf(strlist, "dk%u=adVN=%s,adVF=0xa1,adVU=%s", i++, tmpname, volume->v_uuid); } else { LOG(log_warning, logtype_afpd, "Registering volume '%s' for TimeMachine. But UUID is invalid.", volume->v_localname); strlist = avahi_string_list_add_printf(strlist, "dk%u=adVN=%s,adVF=0xa1", i++, tmpname); } } } /* AFP server */ for (dsi = ctx->obj->dsi; dsi; dsi = dsi->next) { port = getip_port((struct sockaddr *)&dsi->server); LOG(log_info, logtype_afpd, "hostname: %s", ctx->obj->options.hostname); if (convert_string(ctx->obj->options.unixcharset, CH_UTF8, ctx->obj->options.hostname, -1, name, MAXINSTANCENAMELEN) <= 0) { LOG(log_error, logtype_afpd, "Could not set Zeroconf instance name: %s", ctx->obj->options.hostname); goto fail; } if ((dsi->bonjourname = strdup(name)) == NULL) { LOG(log_error, logtype_afpd, "Could not set Zeroconf instance name"); goto fail; } LOG(log_info, logtype_afpd, "Registering server '%s' with Bonjour", dsi->bonjourname); if (avahi_entry_group_add_service(ctx->group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, dsi->bonjourname, AFP_DNS_SERVICE_TYPE, NULL, NULL, port, NULL) < 0) { LOG(log_error, logtype_afpd, "Failed to add service: %s", avahi_strerror(avahi_client_errno(ctx->client))); goto fail; } if (i && avahi_entry_group_add_service_strlst(ctx->group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, dsi->bonjourname, ADISK_SERVICE_TYPE, NULL, NULL, 9, /* discard */ strlist) < 0) { LOG(log_error, logtype_afpd, "Failed to add service: %s", avahi_strerror(avahi_client_errno(ctx->client))); goto fail; } /* if */ if (ctx->obj->options.mimicmodel) { strlist2 = avahi_string_list_add_printf(strlist2, "model=%s", ctx->obj->options.mimicmodel); if (avahi_entry_group_add_service_strlst(ctx->group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, dsi->bonjourname, DEV_INFO_SERVICE_TYPE, NULL, NULL, 0, strlist2) < 0) { LOG(log_error, logtype_afpd, "Failed to add service: %s", avahi_strerror(avahi_client_errno(ctx->client))); goto fail; } } /* if (config->obj.options.mimicmodel) */ } /* for config*/ if (avahi_entry_group_commit(ctx->group) < 0) { LOG(log_error, logtype_afpd, "Failed to commit entry group: %s", avahi_strerror(avahi_client_errno(ctx->client))); goto fail; } } /* if avahi_entry_group_is_empty*/ return; fail: time(NULL); // avahi_threaded_poll_quit(ctx->threaded_poll); }
/* * This function tries to register the AFP DNS * SRV service type. */ static void register_stuff(const AFPObj *obj) { uint port; const struct vol *volume; char name[MAXINSTANCENAMELEN+1]; DNSServiceErrorType error; TXTRecordRef txt_adisk; TXTRecordRef txt_devinfo; char tmpname[256]; // If we had already registered, then we will unregister and re-register if(svc_refs) unregister_stuff(); /* Register our service, prepare the TXT record */ TXTRecordCreate(&txt_adisk, 0, NULL); if( 0 > TXTRecordPrintf(&txt_adisk, "sys", "waMa=0,adVF=0x100") ) { LOG ( log_error, logtype_afpd, "Could not create Zeroconf TXTRecord for sys"); goto fail; } /* Build AFP volumes list */ int i = 0; for (volume = getvolumes(); volume; volume = volume->v_next) { if (convert_string(CH_UCS2, CH_UTF8_MAC, volume->v_u8mname, -1, tmpname, 255) <= 0) { LOG ( log_error, logtype_afpd, "Could not set Zeroconf volume name for TimeMachine"); goto fail; } if (volume->v_flags & AFPVOL_TM) { if (volume->v_uuid) { LOG(log_info, logtype_afpd, "Registering volume '%s' with UUID: '%s' for TimeMachine", volume->v_localname, volume->v_uuid); if( 0 > TXTRecordKeyPrintf(&txt_adisk, "dk%u", i++, "adVN=%s,adVF=0xa1,adVU=%s", tmpname, volume->v_uuid) ) { LOG ( log_error, logtype_afpd, "Could not set Zeroconf TXTRecord for dk%u", i); goto fail; } } else { LOG(log_warning, logtype_afpd, "Registering volume '%s' for TimeMachine. But UUID is invalid.", volume->v_localname); if( 0 > TXTRecordKeyPrintf(&txt_adisk, "dk%u", i++, "adVN=%s,adVF=0xa1", tmpname) ) { LOG ( log_error, logtype_afpd, "Could not set Zeroconf TXTRecord for dk%u", i); goto fail; } } } } /* AFP_DNS_SERVICE_TYPE */ svc_ref_count = 1; if (i) { /* ADISK_SERVICE_TYPE */ svc_ref_count++; } if (obj->options.mimicmodel) { /* DEV_INFO_SERVICE_TYPE */ svc_ref_count++; } // Allocate the memory to store our service refs svc_refs = calloc(svc_ref_count, sizeof(DNSServiceRef)); assert(svc_refs); svc_ref_count = 0; port = atoi(obj->options.port); if (convert_string(obj->options.unixcharset, CH_UTF8, obj->options.hostname, -1, name, MAXINSTANCENAMELEN) <= 0) { LOG(log_error, logtype_afpd, "Could not set Zeroconf instance name"); goto fail; } error = DNSServiceRegister(&svc_refs[svc_ref_count++], 0, // no flags 0, // all network interfaces name, AFP_DNS_SERVICE_TYPE, "", // default domains NULL, // default host name htons(port), 0, // length of TXT NULL, // no TXT RegisterReply, // callback NULL); // no context if (error != kDNSServiceErr_NoError) { LOG(log_error, logtype_afpd, "Failed to add service: %s, error=%d", AFP_DNS_SERVICE_TYPE, error); goto fail; } if (i) { error = DNSServiceRegister(&svc_refs[svc_ref_count++], 0, // no flags 0, // all network interfaces name, ADISK_SERVICE_TYPE, "", // default domains NULL, // default host name htons(port), TXTRecordGetLength(&txt_adisk), TXTRecordGetBytesPtr(&txt_adisk), RegisterReply, // callback NULL); // no context if (error != kDNSServiceErr_NoError) { LOG(log_error, logtype_afpd, "Failed to add service: %s, error=%d", ADISK_SERVICE_TYPE, error); goto fail; } } if (obj->options.mimicmodel) { LOG(log_info, logtype_afpd, "Registering server as model '%s'", obj->options.mimicmodel); TXTRecordCreate(&txt_devinfo, 0, NULL); if ( 0 > TXTRecordPrintf(&txt_devinfo, "model", obj->options.mimicmodel) ) { LOG ( log_error, logtype_afpd, "Could not create Zeroconf TXTRecord for model"); goto fail; } error = DNSServiceRegister(&svc_refs[svc_ref_count++], 0, // no flags 0, // all network interfaces name, DEV_INFO_SERVICE_TYPE, "", // default domains NULL, // default host name /* * We would probably use port 0 zero, but we can't, from man DNSServiceRegister: * "A value of 0 for a port is passed to register placeholder services. * Place holder services are not found when browsing, but other * clients cannot register with the same name as the placeholder service." * We therefor use port 9 which is used by the adisk service type. */ htons(9), TXTRecordGetLength(&txt_devinfo), TXTRecordGetBytesPtr(&txt_devinfo), RegisterReply, // callback NULL); // no context TXTRecordDeallocate(&txt_devinfo); if (error != kDNSServiceErr_NoError) { LOG(log_error, logtype_afpd, "Failed to add service: %s, error=%d", DEV_INFO_SERVICE_TYPE, error); goto fail; } } /* if (config->obj.options.mimicmodel) */ /* * Now we can create the thread that will poll for the results * and handle the calling of the callbacks */ if(pthread_create(&poller, NULL, polling_thread, NULL) != 0) { LOG(log_error, logtype_afpd, "Unable to start mDNS polling thread"); goto fail; } fail: TXTRecordDeallocate(&txt_adisk); return; }