/* * Copyright (C) 2005-2013 Team XBMC * http://xbmc.org * * 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 "system.h" //HAS_ZEROCONF define #include #include "Zeroconf.h" #include "settings/Settings.h" #if defined(HAS_AVAHI) #include "linux/ZeroconfAvahi.h" #elif defined(TARGET_DARWIN) //on osx use the native implementation #include "osx/ZeroconfOSX.h" #elif defined(HAS_MDNS) #include "mdns/ZeroconfMDNS.h" #endif #include "threads/CriticalSection.h" #include "threads/SingleLock.h" #include "threads/Atomics.h" #include "utils/JobManager.h" #ifndef HAS_ZEROCONF //dummy implementation used if no zeroconf is present //should be optimized away class CZeroconfDummy : public CZeroconf { virtual bool doPublishService(const std::string&, const std::string&, const std::string&, unsigned int, const std::vector >&) { return false; } virtual bool doForceReAnnounceService(const std::string&){return false;} virtual bool doRemoveService(const std::string& fcr_ident){return false;} virtual void doStop(){} }; #endif long CZeroconf::sm_singleton_guard = 0; CZeroconf* CZeroconf::smp_instance = 0; CZeroconf::CZeroconf():mp_crit_sec(new CCriticalSection),m_started(false) { } CZeroconf::~CZeroconf() { delete mp_crit_sec; } bool CZeroconf::PublishService(const std::string& fcr_identifier, const std::string& fcr_type, const std::string& fcr_name, unsigned int f_port, std::vector > txt /* = std::vector >() */) { CSingleLock lock(*mp_crit_sec); CZeroconf::PublishInfo info = {fcr_type, fcr_name, f_port, txt}; std::pair ret = m_service_map.insert(std::make_pair(fcr_identifier, info)); if(!ret.second) //identifier exists return false; if(m_started) CJobManager::GetInstance().AddJob(new CPublish(fcr_identifier, info), NULL); //not yet started, so its just queued return true; } bool CZeroconf::RemoveService(const std::string& fcr_identifier) { CSingleLock lock(*mp_crit_sec); tServiceMap::iterator it = m_service_map.find(fcr_identifier); if(it == m_service_map.end()) return false; m_service_map.erase(it); if(m_started) return doRemoveService(fcr_identifier); else return true; } bool CZeroconf::ForceReAnnounceService(const std::string& fcr_identifier) { if (HasService(fcr_identifier) && m_started) { return doForceReAnnounceService(fcr_identifier); } return false; } bool CZeroconf::HasService(const std::string& fcr_identifier) const { return (m_service_map.find(fcr_identifier) != m_service_map.end()); } bool CZeroconf::Start() { CSingleLock lock(*mp_crit_sec); if(!IsZCdaemonRunning()) { CSettings::Get().SetBool("services.zeroconf", false); if (CSettings::Get().GetBool("services.airplay")) CSettings::Get().SetBool("services.airplay", false); return false; } if(m_started) return true; m_started = true; CJobManager::GetInstance().AddJob(new CPublish(m_service_map), NULL); return true; } void CZeroconf::Stop() { CSingleLock lock(*mp_crit_sec); if(!m_started) return; doStop(); m_started = false; } CZeroconf* CZeroconf::GetInstance() { CAtomicSpinLock lock(sm_singleton_guard); if(!smp_instance) { #ifndef HAS_ZEROCONF smp_instance = new CZeroconfDummy; #else #if defined(TARGET_DARWIN) smp_instance = new CZeroconfOSX; #elif defined(HAS_AVAHI) smp_instance = new CZeroconfAvahi; #elif defined(HAS_MDNS) smp_instance = new CZeroconfMDNS; #endif #endif } assert(smp_instance); return smp_instance; } void CZeroconf::ReleaseInstance() { CAtomicSpinLock lock(sm_singleton_guard); delete smp_instance; smp_instance = 0; } CZeroconf::CPublish::CPublish(const std::string& fcr_identifier, const PublishInfo& pubinfo) { m_servmap.insert(std::make_pair(fcr_identifier, pubinfo)); } CZeroconf::CPublish::CPublish(const tServiceMap& servmap) : m_servmap(servmap) { } bool CZeroconf::CPublish::DoWork() { for(tServiceMap::const_iterator it = m_servmap.begin(); it != m_servmap.end(); ++it) CZeroconf::GetInstance()->doPublishService(it->first, it->second.type, it->second.name, it->second.port, it->second.txt); return true; }