static void bonjour_start_service(CFNetServiceRef *svc, char *service_type, uint32_t port, txt_rec_t *txt) { CFStringRef str; CFStreamError error = {0}; CFNetServiceClientContext context = {0, NULL, NULL, NULL, NULL}; str = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, service_type, kCFStringEncodingASCII, kCFAllocatorNull); *svc = CFNetServiceCreate(NULL, CFSTR(""), str, CFSTR("Tvheadend"), port); if (!*svc) { tvhlog(LOG_ERR, "bonjour", "service creation failed"); return; } CFNetServiceSetClient(*svc, bonjour_callback, &context); CFNetServiceScheduleWithRunLoop(*svc, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); if (txt) { CFDataRef data = NULL; CFMutableDictionaryRef dict; dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); while(txt->key) { str = CFStringCreateWithCString (NULL, txt->key, kCFStringEncodingASCII); data = CFDataCreate (NULL, (uint8_t *) txt->value, strlen(txt->value)); CFDictionaryAddValue(dict, str, data); txt++; } data = CFNetServiceCreateTXTDataWithDictionary(NULL, dict); CFNetServiceSetTXTData(*svc, data); CFRelease(data); CFRelease(dict); } if (!CFNetServiceRegisterWithOptions(*svc, 0, &error)) tvhlog(LOG_ERR, "bonjour", "registration failed (service type = %s, " "domain = %ld, error =%d)", service_type, error.domain, error.error); else tvhlog(LOG_INFO, "bonjour", "service '%s' successfully established", service_type); }
//methods to implement for concrete implementations bool CZeroconfOSX::doPublishService(const std::string& fcr_identifier, const std::string& fcr_type, const std::string& fcr_name, unsigned int f_port, std::map<std::string, std::string> txt) { CLog::Log(LOGDEBUG, "CZeroconfOSX::doPublishService identifier: %s type: %s name:%s port:%i", fcr_identifier.c_str(), fcr_type.c_str(), fcr_name.c_str(), f_port); CFStringRef name = CFStringCreateWithCString (NULL, fcr_name.c_str(), kCFStringEncodingUTF8 ); CFStringRef type = CFStringCreateWithCString (NULL, fcr_type.c_str(), kCFStringEncodingUTF8 ); CFNetServiceRef netService = CFNetServiceCreate(NULL, CFSTR(""), type, name, f_port); CFRelease(name); CFRelease(type); //now register it CFNetServiceClientContext clientContext = { 0, this, NULL, NULL, NULL }; CFStreamError error; CFNetServiceSetClient(netService, registerCallback, &clientContext); CFNetServiceScheduleWithRunLoop(netService, m_runloop, kCFRunLoopCommonModes); //add txt records if(!txt.empty()) { //txt map to dictionary CFDataRef txtData = NULL; CFMutableDictionaryRef txtDict = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); for(std::map<std::string, std::string>::const_iterator it = txt.begin(); it != txt.end(); ++it) { CFStringRef key = CFStringCreateWithCString (NULL, it->first.c_str(), kCFStringEncodingUTF8 ); CFDataRef value = CFDataCreate ( NULL, (UInt8 *)it->second.c_str(), strlen(it->second.c_str()) ); CFDictionaryAddValue(txtDict,key, value); } //add txt records to service txtData = CFNetServiceCreateTXTDataWithDictionary(NULL, txtDict); CFNetServiceSetTXTData(netService, txtData); CFRelease(txtData); CFRelease(txtDict); } Boolean result = CFNetServiceRegisterWithOptions (netService, 0, &error); if (result == false) { // Something went wrong so lets clean up. CFNetServiceUnscheduleFromRunLoop(netService, m_runloop, kCFRunLoopCommonModes); CFNetServiceSetClient(netService, NULL, NULL); CFRelease(netService); netService = NULL; CLog::Log(LOGERROR, "CZeroconfOSX::doPublishService CFNetServiceRegister returned " "(domain = %d, error = %"PRId64")", (int)error.domain, (int64_t)error.error); } else { CSingleLock lock(m_data_guard); m_services.insert(make_pair(fcr_identifier, netService)); } return result; }