From 7fbeeed1a120d11b14ae56f2d563f45621832b7d Mon Sep 17 00:00:00 2001 From: Anton Fedchin Date: Tue, 3 Apr 2018 18:26:14 +0300 Subject: [darwin] network: move implementation to platform folder. --- cmake/treedata/ios/subdirs.txt | 2 +- cmake/treedata/osx/subdirs.txt | 2 +- xbmc/network/Zeroconf.cpp | 2 +- xbmc/network/ZeroconfBrowser.cpp | 2 +- xbmc/network/osx/CMakeLists.txt | 8 - xbmc/network/osx/ZeroconfBrowserOSX.cpp | 351 --------------------- xbmc/network/osx/ZeroconfBrowserOSX.h | 78 ----- xbmc/network/osx/ZeroconfOSX.cpp | 209 ------------ xbmc/network/osx/ZeroconfOSX.h | 65 ---- xbmc/network/osx/ioshacks.h | 70 ---- xbmc/platform/darwin/osx/network/CMakeLists.txt | 8 + .../darwin/osx/network/ZeroconfBrowserOSX.cpp | 351 +++++++++++++++++++++ .../darwin/osx/network/ZeroconfBrowserOSX.h | 78 +++++ xbmc/platform/darwin/osx/network/ZeroconfOSX.cpp | 209 ++++++++++++ xbmc/platform/darwin/osx/network/ZeroconfOSX.h | 65 ++++ xbmc/platform/darwin/osx/network/ioshacks.h | 70 ++++ xbmc/platform/linux/network/NetworkLinux.cpp | 2 +- 17 files changed, 786 insertions(+), 786 deletions(-) delete mode 100644 xbmc/network/osx/CMakeLists.txt delete mode 100644 xbmc/network/osx/ZeroconfBrowserOSX.cpp delete mode 100644 xbmc/network/osx/ZeroconfBrowserOSX.h delete mode 100644 xbmc/network/osx/ZeroconfOSX.cpp delete mode 100644 xbmc/network/osx/ZeroconfOSX.h delete mode 100644 xbmc/network/osx/ioshacks.h create mode 100644 xbmc/platform/darwin/osx/network/CMakeLists.txt create mode 100644 xbmc/platform/darwin/osx/network/ZeroconfBrowserOSX.cpp create mode 100644 xbmc/platform/darwin/osx/network/ZeroconfBrowserOSX.h create mode 100644 xbmc/platform/darwin/osx/network/ZeroconfOSX.cpp create mode 100644 xbmc/platform/darwin/osx/network/ZeroconfOSX.h create mode 100644 xbmc/platform/darwin/osx/network/ioshacks.h diff --git a/cmake/treedata/ios/subdirs.txt b/cmake/treedata/ios/subdirs.txt index 652854cbb0..5ac22d903c 100644 --- a/cmake/treedata/ios/subdirs.txt +++ b/cmake/treedata/ios/subdirs.txt @@ -2,13 +2,13 @@ xbmc/platform/linux platform/linux xbmc/platform/linux/network platform/linux/network xbmc/input/touch input/touch xbmc/input/touch/generic input/touch/generic -xbmc/network/osx network/osx xbmc/peripherals/bus/osx peripherals/bus/osx xbmc/powermanagement/osx powermanagement/osx xbmc/platform/posix posix xbmc/platform/darwin platform/darwin xbmc/platform/darwin/ios platform/ios xbmc/platform/darwin/ios-common platform/ios-common +xbmc/platform/darwin/osx/network platform/osx/network xbmc/platform/darwin/osx/storage platform/osx/storage xbmc/filesystem/posix filesystem/posix xbmc/utils/posix utils/posix diff --git a/cmake/treedata/osx/subdirs.txt b/cmake/treedata/osx/subdirs.txt index c58921d2af..53e2608e3a 100644 --- a/cmake/treedata/osx/subdirs.txt +++ b/cmake/treedata/osx/subdirs.txt @@ -1,11 +1,11 @@ xbmc/platform/linux platform/linux xbmc/platform/linux/network platform/linux/network -xbmc/network/osx network/osx xbmc/peripherals/bus/osx peripherals/bus/osx xbmc/powermanagement/osx powermanagement/osx xbmc/platform/posix posix xbmc/platform/darwin platform/darwin xbmc/platform/darwin/osx platform/osx +xbmc/platform/darwin/osx/network platform/osx/network xbmc/platform/darwin/osx/storage platform/osx/storage xbmc/filesystem/posix filesystem/posix xbmc/utils/posix utils/posix diff --git a/xbmc/network/Zeroconf.cpp b/xbmc/network/Zeroconf.cpp index e86c4ea001..b0c1b54575 100644 --- a/xbmc/network/Zeroconf.cpp +++ b/xbmc/network/Zeroconf.cpp @@ -32,7 +32,7 @@ #include "platform/linux/network/ZeroconfAvahi.h" #elif defined(TARGET_DARWIN) //on osx use the native implementation -#include "osx/ZeroconfOSX.h" +#include "platform/darwin/osx/network/ZeroconfOSX.h" #elif defined(TARGET_ANDROID) #include "platform/android/network/ZeroconfAndroid.h" #elif defined(HAS_MDNS) diff --git a/xbmc/network/ZeroconfBrowser.cpp b/xbmc/network/ZeroconfBrowser.cpp index 125e7aa597..a89e0151a1 100644 --- a/xbmc/network/ZeroconfBrowser.cpp +++ b/xbmc/network/ZeroconfBrowser.cpp @@ -26,7 +26,7 @@ #include "platform/linux/network/ZeroconfBrowserAvahi.h" #elif defined(TARGET_DARWIN) //on osx use the native implementation -#include "osx/ZeroconfBrowserOSX.h" +#include "platform/darwin/osx/network/ZeroconfBrowserOSX.h" #elif defined(TARGET_ANDROID) #include "platform/android/network/ZeroconfBrowserAndroid.h" #elif defined(HAS_MDNS) diff --git a/xbmc/network/osx/CMakeLists.txt b/xbmc/network/osx/CMakeLists.txt deleted file mode 100644 index 89d83b4108..0000000000 --- a/xbmc/network/osx/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -set(SOURCES ZeroconfBrowserOSX.cpp - ZeroconfOSX.cpp) - -set(HEADERS ioshacks.h - ZeroconfBrowserOSX.h - ZeroconfOSX.h) - -core_add_library(network_osx) diff --git a/xbmc/network/osx/ZeroconfBrowserOSX.cpp b/xbmc/network/osx/ZeroconfBrowserOSX.cpp deleted file mode 100644 index 103e88ae82..0000000000 --- a/xbmc/network/osx/ZeroconfBrowserOSX.cpp +++ /dev/null @@ -1,351 +0,0 @@ -/* - * Copyright (C) 2005-2013 Team XBMC - * http://kodi.tv - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC; see the file COPYING. If not, see - * . - * - */ - -#include "ServiceBroker.h" -#include "ZeroconfBrowserOSX.h" -#include "GUIUserMessages.h" -#include "guilib/GUIComponent.h" -#include "guilib/GUIWindowManager.h" -#include "guilib/GUIMessage.h" -#include "threads/SingleLock.h" -#include "utils/log.h" -#include "platform/darwin/DarwinUtils.h" - -#include -#include - -namespace -{ - //helper for getting a the txt-records list - //returns true on success, false if nothing found or error - CZeroconfBrowser::ZeroconfService::tTxtRecordMap GetTxtRecords(CFNetServiceRef serviceRef) - { - CFIndex idx = 0; - CZeroconfBrowser::ZeroconfService::tTxtRecordMap recordMap; - CFDataRef data = NULL; - - data=CFNetServiceGetTXTData(serviceRef); - if (data != NULL) - { - CFDictionaryRef dict = CFNetServiceCreateDictionaryWithTXTData(kCFAllocatorDefault, data); - if (dict != NULL) - { - CFIndex numValues = 0; - numValues = CFDictionaryGetCount(dict); - if (numValues > 0) - { - CFStringRef keys[numValues]; - CFDataRef values[numValues]; - - CFDictionaryGetKeysAndValues(dict, (const void **)&keys, (const void **)&values); - - for(idx = 0; idx < numValues; idx++) - { - std::string key; - if (CDarwinUtils::CFStringRefToUTF8String(keys[idx], key)) - { - recordMap.insert( - std::make_pair( - key, - std::string((const char *)CFDataGetBytePtr(values[idx])) - ) - ); - } - } - } - CFRelease(dict); - } - } - return recordMap; - } - - //helper to get (first) IP and port from a resolved service - //returns true on success, false on if none was found - bool CopyFirstIPv4Address(CFNetServiceRef serviceRef, std::string &fr_address, int &fr_port) - { - CFIndex idx; - struct sockaddr_in address; - char buffer[256]; - CFArrayRef addressResults = CFNetServiceGetAddressing( (CFNetServiceRef)serviceRef ); - - if ( addressResults != NULL ) - { - CFIndex numAddressResults = CFArrayGetCount( addressResults ); - CFDataRef sockAddrRef = NULL; - struct sockaddr sockHdr; - - for ( idx = 0; idx < numAddressResults; idx++ ) - { - sockAddrRef = (CFDataRef)CFArrayGetValueAtIndex( addressResults, idx ); - if ( sockAddrRef != NULL ) - { - CFDataGetBytes( sockAddrRef, CFRangeMake(0, sizeof(sockHdr)), (UInt8*)&sockHdr ); - switch ( sockHdr.sa_family ) - { - case AF_INET: - CFDataGetBytes( sockAddrRef, CFRangeMake(0, sizeof(address)), (UInt8*)&address ); - if ( inet_ntop(sockHdr.sa_family, &address.sin_addr, buffer, sizeof(buffer)) != NULL ) - { - fr_address = buffer; - fr_port = ntohs(address.sin_port); - return true; - } - break; - case AF_INET6: - default: - break; - } - } - } - } - return false; - } -} - -CZeroconfBrowserOSX::CZeroconfBrowserOSX():m_runloop(0) -{ - //acquire the main threads event loop - m_runloop = CFRunLoopGetMain(); -} - -CZeroconfBrowserOSX::~CZeroconfBrowserOSX() -{ - CSingleLock lock(m_data_guard); - //make sure there are no browsers anymore - for(tBrowserMap::iterator it = m_service_browsers.begin(); it != m_service_browsers.end(); ++it ) - doRemoveServiceType(it->first); -} - -void CZeroconfBrowserOSX::BrowserCallback(CFNetServiceBrowserRef browser, CFOptionFlags flags, CFTypeRef domainOrService, CFStreamError *error, void *info) -{ - assert(info); - - if (error->error == noErr) - { - //make sure we receive a service - assert(!(flags&kCFNetServiceFlagIsDomain)); - CFNetServiceRef service = (CFNetServiceRef)domainOrService; - assert(service); - //get our instance - CZeroconfBrowserOSX* p_this = reinterpret_cast(info); - - //store the service - std::string name, type, domain; - if (!CDarwinUtils::CFStringRefToUTF8String(CFNetServiceGetName(service), name) || - !CDarwinUtils::CFStringRefToUTF8String(CFNetServiceGetType(service), type) || - !CDarwinUtils::CFStringRefToUTF8String(CFNetServiceGetDomain(service), domain)) - { - CLog::Log(LOGWARNING, "CZeroconfBrowserOSX::BrowserCallback failed to convert service strings."); - return; - } - - ZeroconfService s(name, type, domain); - - if (flags & kCFNetServiceFlagRemove) - { - CLog::Log(LOGDEBUG, "CZeroconfBrowserOSX::BrowserCallback service named: %s, type: %s, domain: %s disappeared", - s.GetName().c_str(), s.GetType().c_str(), s.GetDomain().c_str()); - p_this->removeDiscoveredService(browser, flags, s); - } - else - { - CLog::Log(LOGDEBUG, "CZeroconfBrowserOSX::BrowserCallback found service named: %s, type: %s, domain: %s", - s.GetName().c_str(), s.GetType().c_str(), s.GetDomain().c_str()); - p_this->addDiscoveredService(browser, flags, s); - } - if (! (flags & kCFNetServiceFlagMoreComing) ) - { - CGUIMessage message(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE_PATH); - message.SetStringParam("zeroconf://"); - CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(message); - CLog::Log(LOGDEBUG, "CZeroconfBrowserOSX::BrowserCallback sent gui update for path zeroconf://"); - } - } else - { - CLog::Log(LOGERROR, "CZeroconfBrowserOSX::BrowserCallback returned" - "(domain = %d, error = %" PRId64")", (int)error->domain, (int64_t)error->error); - } -} - -/// adds the service to list of found services -void CZeroconfBrowserOSX:: -addDiscoveredService(CFNetServiceBrowserRef browser, CFOptionFlags flags, CZeroconfBrowser::ZeroconfService const &fcr_service) -{ - CSingleLock lock(m_data_guard); - tDiscoveredServicesMap::iterator browserIt = m_discovered_services.find(browser); - if (browserIt == m_discovered_services.end()) - { - //first service by this browser - browserIt = m_discovered_services.insert(make_pair(browser, std::vector >())).first; - } - //search this service - std::vector >& services = browserIt->second; - std::vector >::iterator serviceIt = services.begin(); - for( ; serviceIt != services.end(); ++serviceIt) - { - if (serviceIt->first == fcr_service) - break; - } - if (serviceIt == services.end()) - services.push_back(std::make_pair(fcr_service, 1)); - else - ++serviceIt->second; -} - -void CZeroconfBrowserOSX:: -removeDiscoveredService(CFNetServiceBrowserRef browser, CFOptionFlags flags, CZeroconfBrowser::ZeroconfService const &fcr_service) -{ - CSingleLock lock(m_data_guard); - tDiscoveredServicesMap::iterator browserIt = m_discovered_services.find(browser); - assert(browserIt != m_discovered_services.end()); - //search this service - std::vector >& services = browserIt->second; - std::vector >::iterator serviceIt = services.begin(); - for( ; serviceIt != services.end(); ++serviceIt) - if (serviceIt->first == fcr_service) - break; - if (serviceIt != services.end()) - { - //decrease refCount - --serviceIt->second; - if (!serviceIt->second) - { - //eventually remove the service - services.erase(serviceIt); - } - } - else - { - //looks like we missed the announce, no problem though.. - } -} - - -bool CZeroconfBrowserOSX::doAddServiceType(const std::string& fcr_service_type) -{ - CFNetServiceClientContext clientContext = { 0, this, NULL, NULL, NULL }; - CFStringRef domain = CFSTR(""); - CFNetServiceBrowserRef p_browser = CFNetServiceBrowserCreate(kCFAllocatorDefault, - CZeroconfBrowserOSX::BrowserCallback, &clientContext); - assert(p_browser != NULL); - - //schedule the browser - CFNetServiceBrowserScheduleWithRunLoop(p_browser, m_runloop, kCFRunLoopCommonModes); - CFStreamError error; - CFStringRef type = CFStringCreateWithCString(NULL, fcr_service_type.c_str(), kCFStringEncodingUTF8); - - assert(type != NULL); - Boolean result = CFNetServiceBrowserSearchForServices(p_browser, domain, type, &error); - CFRelease(type); - if (result == false) - { - // Something went wrong so lets clean up. - CFNetServiceBrowserUnscheduleFromRunLoop(p_browser, m_runloop, kCFRunLoopCommonModes); - CFRelease(p_browser); - p_browser = NULL; - CLog::Log(LOGERROR, "CFNetServiceBrowserSearchForServices returned" - "(domain = %d, error = %" PRId64")", (int)error.domain, (int64_t)error.error); - } - else - { - //store the browser - CSingleLock lock(m_data_guard); - m_service_browsers.insert(std::make_pair(fcr_service_type, p_browser)); - } - - return result; -} - -bool CZeroconfBrowserOSX::doRemoveServiceType(const std::string &fcr_service_type) -{ - //search for this browser and remove it from the map - CFNetServiceBrowserRef browser = 0; - { - CSingleLock lock(m_data_guard); - tBrowserMap::iterator it = m_service_browsers.find(fcr_service_type); - if (it == m_service_browsers.end()) - return false; - - browser = it->second; - m_service_browsers.erase(it); - } - assert(browser); - - //now kill the browser - CFStreamError streamerror; - CFNetServiceBrowserStopSearch(browser, &streamerror); - CFNetServiceBrowserUnscheduleFromRunLoop(browser, m_runloop, kCFRunLoopCommonModes); - CFNetServiceBrowserInvalidate(browser); - //remove the services of this browser - { - CSingleLock lock(m_data_guard); - tDiscoveredServicesMap::iterator it = m_discovered_services.find(browser); - if (it != m_discovered_services.end()) - m_discovered_services.erase(it); - } - CFRelease(browser); - - return true; -} - -std::vector CZeroconfBrowserOSX::doGetFoundServices() -{ - std::vector ret; - CSingleLock lock(m_data_guard); - for(tDiscoveredServicesMap::const_iterator it = m_discovered_services.begin(); - it != m_discovered_services.end(); ++it) - { - const std::vector >& services = it->second; - for(unsigned int i = 0; i < services.size(); ++i) - { - ret.push_back(services[i].first); - } - } - - return ret; -} - -bool CZeroconfBrowserOSX::doResolveService(CZeroconfBrowser::ZeroconfService &fr_service, double f_timeout) -{ - bool ret = false; - CFStringRef type = CFStringCreateWithCString(NULL, fr_service.GetType().c_str(), kCFStringEncodingUTF8); - - CFStringRef name = CFStringCreateWithCString(NULL, fr_service.GetName().c_str(), kCFStringEncodingUTF8); - - CFStringRef domain = CFStringCreateWithCString(NULL, fr_service.GetDomain().c_str(), kCFStringEncodingUTF8); - - CFNetServiceRef service = CFNetServiceCreate (NULL, domain, type, name, 0); - if (CFNetServiceResolveWithTimeout(service, f_timeout, NULL) ) - { - std::string ip; - int port = 0; - ret = CopyFirstIPv4Address(service, ip, port); - fr_service.SetIP(ip); - fr_service.SetPort(port); - //get txt-record list - fr_service.SetTxtRecords(GetTxtRecords(service)); - } - CFRelease(type); - CFRelease(name); - CFRelease(domain); - CFRelease(service); - - return ret; -} diff --git a/xbmc/network/osx/ZeroconfBrowserOSX.h b/xbmc/network/osx/ZeroconfBrowserOSX.h deleted file mode 100644 index 304f7320af..0000000000 --- a/xbmc/network/osx/ZeroconfBrowserOSX.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2005-2013 Team XBMC - * http://kodi.tv - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC; see the file COPYING. If not, see - * . - * - */ -#pragma once - -#include -#include -#include -#include - -#include "network/ZeroconfBrowser.h" -#include "threads/Thread.h" -#include "threads/CriticalSection.h" - -#include -#if defined(TARGET_DARWIN_OSX) - #include -#else - #include -#endif - -//platform specific implementation of zeroconfbrowser interface using native os x APIs -class CZeroconfBrowserOSX : public CZeroconfBrowser -{ -public: - CZeroconfBrowserOSX(); - ~CZeroconfBrowserOSX(); - -private: - ///implementation if CZeroconfBrowser interface - ///@{ - virtual bool doAddServiceType(const std::string &fcr_service_type); - virtual bool doRemoveServiceType(const std::string &fcr_service_type); - - virtual std::vector doGetFoundServices(); - virtual bool doResolveService(CZeroconfBrowser::ZeroconfService &fr_service, double f_timeout); - ///@} - - /// browser callback - static void BrowserCallback(CFNetServiceBrowserRef browser, CFOptionFlags flags, CFTypeRef domainOrService, CFStreamError *error, void *info); - /// resolve callback - static void ResolveCallback(CFNetServiceRef theService, CFStreamError *error, void *info); - - /// adds the service to list of found services - void addDiscoveredService(CFNetServiceBrowserRef browser, CFOptionFlags flags, ZeroconfService const &fcr_service); - /// removes the service from list of found services - void removeDiscoveredService(CFNetServiceBrowserRef browser, CFOptionFlags flags, ZeroconfService const &fcr_service); - - //CF runloop ref; we're using main-threads runloop - CFRunLoopRef m_runloop; - - //shared variables (with guard) - //! @todo split the guard for discovered, resolved access? - CCriticalSection m_data_guard; - // tBrowserMap maps service types the corresponding browser - typedef std::map tBrowserMap; - tBrowserMap m_service_browsers; - //tDiscoveredServicesMap maps browsers to their discovered services + a ref-count for each service - //ref-count is needed, because a service might pop up more than once, if there's more than one network-iface - typedef std::map > > tDiscoveredServicesMap; - tDiscoveredServicesMap m_discovered_services; -}; diff --git a/xbmc/network/osx/ZeroconfOSX.cpp b/xbmc/network/osx/ZeroconfOSX.cpp deleted file mode 100644 index 12832a074e..0000000000 --- a/xbmc/network/osx/ZeroconfOSX.cpp +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright (C) 2005-2013 Team XBMC - * http://kodi.tv - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC; see the file COPYING. If not, see - * . - * - */ - -#include "ZeroconfOSX.h" -#include "threads/SingleLock.h" -#include "utils/log.h" - -#include -#include - -CZeroconfOSX::CZeroconfOSX():m_runloop(0) -{ - //acquire the main threads event loop - m_runloop = CFRunLoopGetMain(); -} - -CZeroconfOSX::~CZeroconfOSX() -{ - doStop(); -} - -CFHashCode CFHashNullVersion (CFTypeRef cf) -{ - return 0; -} - - -//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, - const std::vector >& 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()) - { - - CFDictionaryKeyCallBacks key_cb = kCFTypeDictionaryKeyCallBacks; - key_cb.hash = CFHashNullVersion; - - //txt map to dictionary - CFDataRef txtData = NULL; - CFMutableDictionaryRef txtDict = CFDictionaryCreateMutable(NULL, 0, &key_cb, &kCFTypeDictionaryValueCallBacks); - for(std::vector >::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); - CFRelease(key); - CFRelease(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; -} - -bool CZeroconfOSX::doForceReAnnounceService(const std::string& fcr_identifier) -{ - bool ret = false; - CSingleLock lock(m_data_guard); - tServiceMap::iterator it = m_services.find(fcr_identifier); - if(it != m_services.end()) - { - CFNetServiceRef service = it->second; - - CFDataRef txtData = CFNetServiceGetTXTData(service); - // convert the txtdata back and forth is enough to trigger a reannounce later - CFDictionaryRef txtDict = CFNetServiceCreateDictionaryWithTXTData(NULL, txtData); - CFMutableDictionaryRef txtDictMutable =CFDictionaryCreateMutableCopy(NULL, 0, txtDict); - txtData = CFNetServiceCreateTXTDataWithDictionary(NULL, txtDictMutable); - - // this triggers the reannounce - ret = CFNetServiceSetTXTData(service, txtData); - - CFRelease(txtDictMutable); - CFRelease(txtDict); - CFRelease(txtData); - } - return ret; -} - - -bool CZeroconfOSX::doRemoveService(const std::string& fcr_ident) -{ - CSingleLock lock(m_data_guard); - tServiceMap::iterator it = m_services.find(fcr_ident); - if(it != m_services.end()) - { - cancelRegistration(it->second); - m_services.erase(it); - return true; - } else - return false; -} - -void CZeroconfOSX::doStop() -{ - CSingleLock lock(m_data_guard); - for(tServiceMap::iterator it = m_services.begin(); it != m_services.end(); ++it) - cancelRegistration(it->second); - m_services.clear(); -} - - -void CZeroconfOSX::registerCallback(CFNetServiceRef theService, CFStreamError* error, void* info) -{ - if (error->domain == kCFStreamErrorDomainNetServices) - { - CZeroconfOSX* p_this = reinterpret_cast(info); - switch(error->error) { - case kCFNetServicesErrorCollision: - CLog::Log(LOGERROR, "CZeroconfOSX::registerCallback name collision occured"); - break; - default: - CLog::Log(LOGERROR, "CZeroconfOSX::registerCallback returned " - "(domain = %d, error = %" PRId64")", (int)error->domain, (int64_t)error->error); - break; - } - p_this->cancelRegistration(theService); - //remove it - CSingleLock lock(p_this->m_data_guard); - for(tServiceMap::iterator it = p_this->m_services.begin(); it != p_this->m_services.end(); ++it) - { - if(it->second == theService) - { - p_this->m_services.erase(it); - break; - } - } - } -} - -void CZeroconfOSX::cancelRegistration(CFNetServiceRef theService) -{ - assert(theService != NULL); - CFNetServiceUnscheduleFromRunLoop(theService, m_runloop, kCFRunLoopCommonModes); - CFNetServiceSetClient(theService, NULL, NULL); - CFNetServiceCancel(theService); - CFRelease(theService); -} diff --git a/xbmc/network/osx/ZeroconfOSX.h b/xbmc/network/osx/ZeroconfOSX.h deleted file mode 100644 index 46a9e04ec9..0000000000 --- a/xbmc/network/osx/ZeroconfOSX.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2005-2013 Team XBMC - * http://kodi.tv - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC; see the file COPYING. If not, see - * . - * - */ -#pragma once - -#include -#include - -#include "network/Zeroconf.h" -#include "threads/CriticalSection.h" - -#include -#if defined(TARGET_DARWIN_OSX) - #include -#else - #include -#endif - -class CZeroconfOSX : public CZeroconf -{ -public: - CZeroconfOSX(); - ~CZeroconfOSX(); -protected: - //implement base CZeroConf interface - bool doPublishService(const std::string& fcr_identifier, - const std::string& fcr_type, - const std::string& fcr_name, - unsigned int f_port, - const std::vector >& txt); - - bool doForceReAnnounceService(const std::string& fcr_identifier); - - bool doRemoveService(const std::string& fcr_ident); - - virtual void doStop(); - -private: - static void registerCallback(CFNetServiceRef theService, CFStreamError* error, void* info); - void cancelRegistration(CFNetServiceRef theService); - - //CF runloop ref; we're using main-threads runloop - CFRunLoopRef m_runloop; - - //lock + data (accessed from runloop(main thread) + the rest) - CCriticalSection m_data_guard; - typedef std::map tServiceMap; - tServiceMap m_services; -}; diff --git a/xbmc/network/osx/ioshacks.h b/xbmc/network/osx/ioshacks.h deleted file mode 100644 index 35fec226dc..0000000000 --- a/xbmc/network/osx/ioshacks.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2013 Team XBMC - * http://kodi.tv - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC; see the file COPYING. If not, see - * . - * - */ - -// needed for CNetworkInterfaceLinux::GetHostMacAddress and taken from osx sdk -// net/if_types.h net/route.h netinet/if_ether.h - -/* - * These numbers are used by reliable protocols for determining - * retransmission behavior and are included in the routing structure. - */ -struct rt_metrics { - u_int32_t rmx_locks; /* Kernel must leave these values alone */ - u_int32_t rmx_mtu; /* MTU for this path */ - u_int32_t rmx_hopcount; /* max hops expected */ - int32_t rmx_expire; /* lifetime for route, e.g. redirect */ - u_int32_t rmx_recvpipe; /* inbound delay-bandwidth product */ - u_int32_t rmx_sendpipe; /* outbound delay-bandwidth product */ - u_int32_t rmx_ssthresh; /* outbound gateway buffer limit */ - u_int32_t rmx_rtt; /* estimated round trip time */ - u_int32_t rmx_rttvar; /* estimated rtt variance */ - u_int32_t rmx_pksent; /* packets sent using this route */ - u_int32_t rmx_filler[4]; /* will be used for T/TCP later */ -}; - -/* - * Structures for routing messages. - */ -struct rt_msghdr { - u_short rtm_msglen; /* to skip over non-understood messages */ - u_char rtm_version; /* future binary compatibility */ - u_char rtm_type; /* message type */ - u_short rtm_index; /* index for associated ifp */ - int rtm_flags; /* flags, incl. kern & message, e.g. DONE */ - int rtm_addrs; /* bitmask identifying sockaddrs in msg */ - pid_t rtm_pid; /* identify sender */ - int rtm_seq; /* for sender to identify action */ - int rtm_errno; /* why failed */ - int rtm_use; /* from rtentry */ - u_int32_t rtm_inits; /* which metrics we are initializing */ - struct rt_metrics rtm_rmx; /* metrics themselves */ -}; -struct sockaddr_inarp { - u_char sin_len; - u_char sin_family; - u_short sin_port; - struct in_addr sin_addr; - struct in_addr sin_srcaddr; - u_short sin_tos; - u_short sin_other; -#define SIN_PROXY 1 -}; -#define RTF_LLINFO 0x400 /* generated by link layer (e.g. ARP) */ -// --- END diff --git a/xbmc/platform/darwin/osx/network/CMakeLists.txt b/xbmc/platform/darwin/osx/network/CMakeLists.txt new file mode 100644 index 0000000000..e0219bbea4 --- /dev/null +++ b/xbmc/platform/darwin/osx/network/CMakeLists.txt @@ -0,0 +1,8 @@ +set(SOURCES ZeroconfBrowserOSX.cpp + ZeroconfOSX.cpp) + +set(HEADERS ioshacks.h + ZeroconfBrowserOSX.h + ZeroconfOSX.h) + +core_add_library(platform_osx_network) diff --git a/xbmc/platform/darwin/osx/network/ZeroconfBrowserOSX.cpp b/xbmc/platform/darwin/osx/network/ZeroconfBrowserOSX.cpp new file mode 100644 index 0000000000..103e88ae82 --- /dev/null +++ b/xbmc/platform/darwin/osx/network/ZeroconfBrowserOSX.cpp @@ -0,0 +1,351 @@ +/* + * Copyright (C) 2005-2013 Team XBMC + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * . + * + */ + +#include "ServiceBroker.h" +#include "ZeroconfBrowserOSX.h" +#include "GUIUserMessages.h" +#include "guilib/GUIComponent.h" +#include "guilib/GUIWindowManager.h" +#include "guilib/GUIMessage.h" +#include "threads/SingleLock.h" +#include "utils/log.h" +#include "platform/darwin/DarwinUtils.h" + +#include +#include + +namespace +{ + //helper for getting a the txt-records list + //returns true on success, false if nothing found or error + CZeroconfBrowser::ZeroconfService::tTxtRecordMap GetTxtRecords(CFNetServiceRef serviceRef) + { + CFIndex idx = 0; + CZeroconfBrowser::ZeroconfService::tTxtRecordMap recordMap; + CFDataRef data = NULL; + + data=CFNetServiceGetTXTData(serviceRef); + if (data != NULL) + { + CFDictionaryRef dict = CFNetServiceCreateDictionaryWithTXTData(kCFAllocatorDefault, data); + if (dict != NULL) + { + CFIndex numValues = 0; + numValues = CFDictionaryGetCount(dict); + if (numValues > 0) + { + CFStringRef keys[numValues]; + CFDataRef values[numValues]; + + CFDictionaryGetKeysAndValues(dict, (const void **)&keys, (const void **)&values); + + for(idx = 0; idx < numValues; idx++) + { + std::string key; + if (CDarwinUtils::CFStringRefToUTF8String(keys[idx], key)) + { + recordMap.insert( + std::make_pair( + key, + std::string((const char *)CFDataGetBytePtr(values[idx])) + ) + ); + } + } + } + CFRelease(dict); + } + } + return recordMap; + } + + //helper to get (first) IP and port from a resolved service + //returns true on success, false on if none was found + bool CopyFirstIPv4Address(CFNetServiceRef serviceRef, std::string &fr_address, int &fr_port) + { + CFIndex idx; + struct sockaddr_in address; + char buffer[256]; + CFArrayRef addressResults = CFNetServiceGetAddressing( (CFNetServiceRef)serviceRef ); + + if ( addressResults != NULL ) + { + CFIndex numAddressResults = CFArrayGetCount( addressResults ); + CFDataRef sockAddrRef = NULL; + struct sockaddr sockHdr; + + for ( idx = 0; idx < numAddressResults; idx++ ) + { + sockAddrRef = (CFDataRef)CFArrayGetValueAtIndex( addressResults, idx ); + if ( sockAddrRef != NULL ) + { + CFDataGetBytes( sockAddrRef, CFRangeMake(0, sizeof(sockHdr)), (UInt8*)&sockHdr ); + switch ( sockHdr.sa_family ) + { + case AF_INET: + CFDataGetBytes( sockAddrRef, CFRangeMake(0, sizeof(address)), (UInt8*)&address ); + if ( inet_ntop(sockHdr.sa_family, &address.sin_addr, buffer, sizeof(buffer)) != NULL ) + { + fr_address = buffer; + fr_port = ntohs(address.sin_port); + return true; + } + break; + case AF_INET6: + default: + break; + } + } + } + } + return false; + } +} + +CZeroconfBrowserOSX::CZeroconfBrowserOSX():m_runloop(0) +{ + //acquire the main threads event loop + m_runloop = CFRunLoopGetMain(); +} + +CZeroconfBrowserOSX::~CZeroconfBrowserOSX() +{ + CSingleLock lock(m_data_guard); + //make sure there are no browsers anymore + for(tBrowserMap::iterator it = m_service_browsers.begin(); it != m_service_browsers.end(); ++it ) + doRemoveServiceType(it->first); +} + +void CZeroconfBrowserOSX::BrowserCallback(CFNetServiceBrowserRef browser, CFOptionFlags flags, CFTypeRef domainOrService, CFStreamError *error, void *info) +{ + assert(info); + + if (error->error == noErr) + { + //make sure we receive a service + assert(!(flags&kCFNetServiceFlagIsDomain)); + CFNetServiceRef service = (CFNetServiceRef)domainOrService; + assert(service); + //get our instance + CZeroconfBrowserOSX* p_this = reinterpret_cast(info); + + //store the service + std::string name, type, domain; + if (!CDarwinUtils::CFStringRefToUTF8String(CFNetServiceGetName(service), name) || + !CDarwinUtils::CFStringRefToUTF8String(CFNetServiceGetType(service), type) || + !CDarwinUtils::CFStringRefToUTF8String(CFNetServiceGetDomain(service), domain)) + { + CLog::Log(LOGWARNING, "CZeroconfBrowserOSX::BrowserCallback failed to convert service strings."); + return; + } + + ZeroconfService s(name, type, domain); + + if (flags & kCFNetServiceFlagRemove) + { + CLog::Log(LOGDEBUG, "CZeroconfBrowserOSX::BrowserCallback service named: %s, type: %s, domain: %s disappeared", + s.GetName().c_str(), s.GetType().c_str(), s.GetDomain().c_str()); + p_this->removeDiscoveredService(browser, flags, s); + } + else + { + CLog::Log(LOGDEBUG, "CZeroconfBrowserOSX::BrowserCallback found service named: %s, type: %s, domain: %s", + s.GetName().c_str(), s.GetType().c_str(), s.GetDomain().c_str()); + p_this->addDiscoveredService(browser, flags, s); + } + if (! (flags & kCFNetServiceFlagMoreComing) ) + { + CGUIMessage message(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE_PATH); + message.SetStringParam("zeroconf://"); + CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(message); + CLog::Log(LOGDEBUG, "CZeroconfBrowserOSX::BrowserCallback sent gui update for path zeroconf://"); + } + } else + { + CLog::Log(LOGERROR, "CZeroconfBrowserOSX::BrowserCallback returned" + "(domain = %d, error = %" PRId64")", (int)error->domain, (int64_t)error->error); + } +} + +/// adds the service to list of found services +void CZeroconfBrowserOSX:: +addDiscoveredService(CFNetServiceBrowserRef browser, CFOptionFlags flags, CZeroconfBrowser::ZeroconfService const &fcr_service) +{ + CSingleLock lock(m_data_guard); + tDiscoveredServicesMap::iterator browserIt = m_discovered_services.find(browser); + if (browserIt == m_discovered_services.end()) + { + //first service by this browser + browserIt = m_discovered_services.insert(make_pair(browser, std::vector >())).first; + } + //search this service + std::vector >& services = browserIt->second; + std::vector >::iterator serviceIt = services.begin(); + for( ; serviceIt != services.end(); ++serviceIt) + { + if (serviceIt->first == fcr_service) + break; + } + if (serviceIt == services.end()) + services.push_back(std::make_pair(fcr_service, 1)); + else + ++serviceIt->second; +} + +void CZeroconfBrowserOSX:: +removeDiscoveredService(CFNetServiceBrowserRef browser, CFOptionFlags flags, CZeroconfBrowser::ZeroconfService const &fcr_service) +{ + CSingleLock lock(m_data_guard); + tDiscoveredServicesMap::iterator browserIt = m_discovered_services.find(browser); + assert(browserIt != m_discovered_services.end()); + //search this service + std::vector >& services = browserIt->second; + std::vector >::iterator serviceIt = services.begin(); + for( ; serviceIt != services.end(); ++serviceIt) + if (serviceIt->first == fcr_service) + break; + if (serviceIt != services.end()) + { + //decrease refCount + --serviceIt->second; + if (!serviceIt->second) + { + //eventually remove the service + services.erase(serviceIt); + } + } + else + { + //looks like we missed the announce, no problem though.. + } +} + + +bool CZeroconfBrowserOSX::doAddServiceType(const std::string& fcr_service_type) +{ + CFNetServiceClientContext clientContext = { 0, this, NULL, NULL, NULL }; + CFStringRef domain = CFSTR(""); + CFNetServiceBrowserRef p_browser = CFNetServiceBrowserCreate(kCFAllocatorDefault, + CZeroconfBrowserOSX::BrowserCallback, &clientContext); + assert(p_browser != NULL); + + //schedule the browser + CFNetServiceBrowserScheduleWithRunLoop(p_browser, m_runloop, kCFRunLoopCommonModes); + CFStreamError error; + CFStringRef type = CFStringCreateWithCString(NULL, fcr_service_type.c_str(), kCFStringEncodingUTF8); + + assert(type != NULL); + Boolean result = CFNetServiceBrowserSearchForServices(p_browser, domain, type, &error); + CFRelease(type); + if (result == false) + { + // Something went wrong so lets clean up. + CFNetServiceBrowserUnscheduleFromRunLoop(p_browser, m_runloop, kCFRunLoopCommonModes); + CFRelease(p_browser); + p_browser = NULL; + CLog::Log(LOGERROR, "CFNetServiceBrowserSearchForServices returned" + "(domain = %d, error = %" PRId64")", (int)error.domain, (int64_t)error.error); + } + else + { + //store the browser + CSingleLock lock(m_data_guard); + m_service_browsers.insert(std::make_pair(fcr_service_type, p_browser)); + } + + return result; +} + +bool CZeroconfBrowserOSX::doRemoveServiceType(const std::string &fcr_service_type) +{ + //search for this browser and remove it from the map + CFNetServiceBrowserRef browser = 0; + { + CSingleLock lock(m_data_guard); + tBrowserMap::iterator it = m_service_browsers.find(fcr_service_type); + if (it == m_service_browsers.end()) + return false; + + browser = it->second; + m_service_browsers.erase(it); + } + assert(browser); + + //now kill the browser + CFStreamError streamerror; + CFNetServiceBrowserStopSearch(browser, &streamerror); + CFNetServiceBrowserUnscheduleFromRunLoop(browser, m_runloop, kCFRunLoopCommonModes); + CFNetServiceBrowserInvalidate(browser); + //remove the services of this browser + { + CSingleLock lock(m_data_guard); + tDiscoveredServicesMap::iterator it = m_discovered_services.find(browser); + if (it != m_discovered_services.end()) + m_discovered_services.erase(it); + } + CFRelease(browser); + + return true; +} + +std::vector CZeroconfBrowserOSX::doGetFoundServices() +{ + std::vector ret; + CSingleLock lock(m_data_guard); + for(tDiscoveredServicesMap::const_iterator it = m_discovered_services.begin(); + it != m_discovered_services.end(); ++it) + { + const std::vector >& services = it->second; + for(unsigned int i = 0; i < services.size(); ++i) + { + ret.push_back(services[i].first); + } + } + + return ret; +} + +bool CZeroconfBrowserOSX::doResolveService(CZeroconfBrowser::ZeroconfService &fr_service, double f_timeout) +{ + bool ret = false; + CFStringRef type = CFStringCreateWithCString(NULL, fr_service.GetType().c_str(), kCFStringEncodingUTF8); + + CFStringRef name = CFStringCreateWithCString(NULL, fr_service.GetName().c_str(), kCFStringEncodingUTF8); + + CFStringRef domain = CFStringCreateWithCString(NULL, fr_service.GetDomain().c_str(), kCFStringEncodingUTF8); + + CFNetServiceRef service = CFNetServiceCreate (NULL, domain, type, name, 0); + if (CFNetServiceResolveWithTimeout(service, f_timeout, NULL) ) + { + std::string ip; + int port = 0; + ret = CopyFirstIPv4Address(service, ip, port); + fr_service.SetIP(ip); + fr_service.SetPort(port); + //get txt-record list + fr_service.SetTxtRecords(GetTxtRecords(service)); + } + CFRelease(type); + CFRelease(name); + CFRelease(domain); + CFRelease(service); + + return ret; +} diff --git a/xbmc/platform/darwin/osx/network/ZeroconfBrowserOSX.h b/xbmc/platform/darwin/osx/network/ZeroconfBrowserOSX.h new file mode 100644 index 0000000000..304f7320af --- /dev/null +++ b/xbmc/platform/darwin/osx/network/ZeroconfBrowserOSX.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2005-2013 Team XBMC + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * . + * + */ +#pragma once + +#include +#include +#include +#include + +#include "network/ZeroconfBrowser.h" +#include "threads/Thread.h" +#include "threads/CriticalSection.h" + +#include +#if defined(TARGET_DARWIN_OSX) + #include +#else + #include +#endif + +//platform specific implementation of zeroconfbrowser interface using native os x APIs +class CZeroconfBrowserOSX : public CZeroconfBrowser +{ +public: + CZeroconfBrowserOSX(); + ~CZeroconfBrowserOSX(); + +private: + ///implementation if CZeroconfBrowser interface + ///@{ + virtual bool doAddServiceType(const std::string &fcr_service_type); + virtual bool doRemoveServiceType(const std::string &fcr_service_type); + + virtual std::vector doGetFoundServices(); + virtual bool doResolveService(CZeroconfBrowser::ZeroconfService &fr_service, double f_timeout); + ///@} + + /// browser callback + static void BrowserCallback(CFNetServiceBrowserRef browser, CFOptionFlags flags, CFTypeRef domainOrService, CFStreamError *error, void *info); + /// resolve callback + static void ResolveCallback(CFNetServiceRef theService, CFStreamError *error, void *info); + + /// adds the service to list of found services + void addDiscoveredService(CFNetServiceBrowserRef browser, CFOptionFlags flags, ZeroconfService const &fcr_service); + /// removes the service from list of found services + void removeDiscoveredService(CFNetServiceBrowserRef browser, CFOptionFlags flags, ZeroconfService const &fcr_service); + + //CF runloop ref; we're using main-threads runloop + CFRunLoopRef m_runloop; + + //shared variables (with guard) + //! @todo split the guard for discovered, resolved access? + CCriticalSection m_data_guard; + // tBrowserMap maps service types the corresponding browser + typedef std::map tBrowserMap; + tBrowserMap m_service_browsers; + //tDiscoveredServicesMap maps browsers to their discovered services + a ref-count for each service + //ref-count is needed, because a service might pop up more than once, if there's more than one network-iface + typedef std::map > > tDiscoveredServicesMap; + tDiscoveredServicesMap m_discovered_services; +}; diff --git a/xbmc/platform/darwin/osx/network/ZeroconfOSX.cpp b/xbmc/platform/darwin/osx/network/ZeroconfOSX.cpp new file mode 100644 index 0000000000..12832a074e --- /dev/null +++ b/xbmc/platform/darwin/osx/network/ZeroconfOSX.cpp @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2005-2013 Team XBMC + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * . + * + */ + +#include "ZeroconfOSX.h" +#include "threads/SingleLock.h" +#include "utils/log.h" + +#include +#include + +CZeroconfOSX::CZeroconfOSX():m_runloop(0) +{ + //acquire the main threads event loop + m_runloop = CFRunLoopGetMain(); +} + +CZeroconfOSX::~CZeroconfOSX() +{ + doStop(); +} + +CFHashCode CFHashNullVersion (CFTypeRef cf) +{ + return 0; +} + + +//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, + const std::vector >& 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()) + { + + CFDictionaryKeyCallBacks key_cb = kCFTypeDictionaryKeyCallBacks; + key_cb.hash = CFHashNullVersion; + + //txt map to dictionary + CFDataRef txtData = NULL; + CFMutableDictionaryRef txtDict = CFDictionaryCreateMutable(NULL, 0, &key_cb, &kCFTypeDictionaryValueCallBacks); + for(std::vector >::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); + CFRelease(key); + CFRelease(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; +} + +bool CZeroconfOSX::doForceReAnnounceService(const std::string& fcr_identifier) +{ + bool ret = false; + CSingleLock lock(m_data_guard); + tServiceMap::iterator it = m_services.find(fcr_identifier); + if(it != m_services.end()) + { + CFNetServiceRef service = it->second; + + CFDataRef txtData = CFNetServiceGetTXTData(service); + // convert the txtdata back and forth is enough to trigger a reannounce later + CFDictionaryRef txtDict = CFNetServiceCreateDictionaryWithTXTData(NULL, txtData); + CFMutableDictionaryRef txtDictMutable =CFDictionaryCreateMutableCopy(NULL, 0, txtDict); + txtData = CFNetServiceCreateTXTDataWithDictionary(NULL, txtDictMutable); + + // this triggers the reannounce + ret = CFNetServiceSetTXTData(service, txtData); + + CFRelease(txtDictMutable); + CFRelease(txtDict); + CFRelease(txtData); + } + return ret; +} + + +bool CZeroconfOSX::doRemoveService(const std::string& fcr_ident) +{ + CSingleLock lock(m_data_guard); + tServiceMap::iterator it = m_services.find(fcr_ident); + if(it != m_services.end()) + { + cancelRegistration(it->second); + m_services.erase(it); + return true; + } else + return false; +} + +void CZeroconfOSX::doStop() +{ + CSingleLock lock(m_data_guard); + for(tServiceMap::iterator it = m_services.begin(); it != m_services.end(); ++it) + cancelRegistration(it->second); + m_services.clear(); +} + + +void CZeroconfOSX::registerCallback(CFNetServiceRef theService, CFStreamError* error, void* info) +{ + if (error->domain == kCFStreamErrorDomainNetServices) + { + CZeroconfOSX* p_this = reinterpret_cast(info); + switch(error->error) { + case kCFNetServicesErrorCollision: + CLog::Log(LOGERROR, "CZeroconfOSX::registerCallback name collision occured"); + break; + default: + CLog::Log(LOGERROR, "CZeroconfOSX::registerCallback returned " + "(domain = %d, error = %" PRId64")", (int)error->domain, (int64_t)error->error); + break; + } + p_this->cancelRegistration(theService); + //remove it + CSingleLock lock(p_this->m_data_guard); + for(tServiceMap::iterator it = p_this->m_services.begin(); it != p_this->m_services.end(); ++it) + { + if(it->second == theService) + { + p_this->m_services.erase(it); + break; + } + } + } +} + +void CZeroconfOSX::cancelRegistration(CFNetServiceRef theService) +{ + assert(theService != NULL); + CFNetServiceUnscheduleFromRunLoop(theService, m_runloop, kCFRunLoopCommonModes); + CFNetServiceSetClient(theService, NULL, NULL); + CFNetServiceCancel(theService); + CFRelease(theService); +} diff --git a/xbmc/platform/darwin/osx/network/ZeroconfOSX.h b/xbmc/platform/darwin/osx/network/ZeroconfOSX.h new file mode 100644 index 0000000000..46a9e04ec9 --- /dev/null +++ b/xbmc/platform/darwin/osx/network/ZeroconfOSX.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2005-2013 Team XBMC + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * . + * + */ +#pragma once + +#include +#include + +#include "network/Zeroconf.h" +#include "threads/CriticalSection.h" + +#include +#if defined(TARGET_DARWIN_OSX) + #include +#else + #include +#endif + +class CZeroconfOSX : public CZeroconf +{ +public: + CZeroconfOSX(); + ~CZeroconfOSX(); +protected: + //implement base CZeroConf interface + bool doPublishService(const std::string& fcr_identifier, + const std::string& fcr_type, + const std::string& fcr_name, + unsigned int f_port, + const std::vector >& txt); + + bool doForceReAnnounceService(const std::string& fcr_identifier); + + bool doRemoveService(const std::string& fcr_ident); + + virtual void doStop(); + +private: + static void registerCallback(CFNetServiceRef theService, CFStreamError* error, void* info); + void cancelRegistration(CFNetServiceRef theService); + + //CF runloop ref; we're using main-threads runloop + CFRunLoopRef m_runloop; + + //lock + data (accessed from runloop(main thread) + the rest) + CCriticalSection m_data_guard; + typedef std::map tServiceMap; + tServiceMap m_services; +}; diff --git a/xbmc/platform/darwin/osx/network/ioshacks.h b/xbmc/platform/darwin/osx/network/ioshacks.h new file mode 100644 index 0000000000..35fec226dc --- /dev/null +++ b/xbmc/platform/darwin/osx/network/ioshacks.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2013 Team XBMC + * http://kodi.tv + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, see + * . + * + */ + +// needed for CNetworkInterfaceLinux::GetHostMacAddress and taken from osx sdk +// net/if_types.h net/route.h netinet/if_ether.h + +/* + * These numbers are used by reliable protocols for determining + * retransmission behavior and are included in the routing structure. + */ +struct rt_metrics { + u_int32_t rmx_locks; /* Kernel must leave these values alone */ + u_int32_t rmx_mtu; /* MTU for this path */ + u_int32_t rmx_hopcount; /* max hops expected */ + int32_t rmx_expire; /* lifetime for route, e.g. redirect */ + u_int32_t rmx_recvpipe; /* inbound delay-bandwidth product */ + u_int32_t rmx_sendpipe; /* outbound delay-bandwidth product */ + u_int32_t rmx_ssthresh; /* outbound gateway buffer limit */ + u_int32_t rmx_rtt; /* estimated round trip time */ + u_int32_t rmx_rttvar; /* estimated rtt variance */ + u_int32_t rmx_pksent; /* packets sent using this route */ + u_int32_t rmx_filler[4]; /* will be used for T/TCP later */ +}; + +/* + * Structures for routing messages. + */ +struct rt_msghdr { + u_short rtm_msglen; /* to skip over non-understood messages */ + u_char rtm_version; /* future binary compatibility */ + u_char rtm_type; /* message type */ + u_short rtm_index; /* index for associated ifp */ + int rtm_flags; /* flags, incl. kern & message, e.g. DONE */ + int rtm_addrs; /* bitmask identifying sockaddrs in msg */ + pid_t rtm_pid; /* identify sender */ + int rtm_seq; /* for sender to identify action */ + int rtm_errno; /* why failed */ + int rtm_use; /* from rtentry */ + u_int32_t rtm_inits; /* which metrics we are initializing */ + struct rt_metrics rtm_rmx; /* metrics themselves */ +}; +struct sockaddr_inarp { + u_char sin_len; + u_char sin_family; + u_short sin_port; + struct in_addr sin_addr; + struct in_addr sin_srcaddr; + u_short sin_tos; + u_short sin_other; +#define SIN_PROXY 1 +}; +#define RTF_LLINFO 0x400 /* generated by link layer (e.g. ARP) */ +// --- END diff --git a/xbmc/platform/linux/network/NetworkLinux.cpp b/xbmc/platform/linux/network/NetworkLinux.cpp index 9771763818..13d973f18c 100644 --- a/xbmc/platform/linux/network/NetworkLinux.cpp +++ b/xbmc/platform/linux/network/NetworkLinux.cpp @@ -45,7 +45,7 @@ #include #include #else //IOS - #include "network/osx/ioshacks.h" + #include "platform/darwin/osx/network/ioshacks.h" #endif #include #elif defined(TARGET_FREEBSD) -- cgit v1.2.3