Merge pull request #4775 from jmarshallnz/empty_episode_playcount
[vuplus_xbmc] / xbmc / network / Zeroconf.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20 #include "system.h" //HAS_ZEROCONF define
21 #include <assert.h>
22 #include "Zeroconf.h"
23 #include "settings/Settings.h"
24
25 #if defined(HAS_AVAHI)
26 #include "linux/ZeroconfAvahi.h"
27 #elif defined(TARGET_DARWIN)
28 //on osx use the native implementation
29 #include "osx/ZeroconfOSX.h"
30 #elif defined(HAS_MDNS)
31 #include "mdns/ZeroconfMDNS.h"
32 #endif
33
34 #include "threads/CriticalSection.h"
35 #include "threads/SingleLock.h"
36 #include "threads/Atomics.h"
37 #include "utils/JobManager.h"
38
39 #ifndef HAS_ZEROCONF
40 //dummy implementation used if no zeroconf is present
41 //should be optimized away
42 class CZeroconfDummy : public CZeroconf
43 {
44   virtual bool doPublishService(const std::string&, const std::string&, const std::string&, unsigned int, const std::vector<std::pair<std::string, std::string> >&)
45   {
46     return false;
47   }
48
49   virtual bool doForceReAnnounceService(const std::string&){return false;} 
50   virtual bool doRemoveService(const std::string& fcr_ident){return false;}
51   virtual void doStop(){}
52 };
53 #endif
54
55 long CZeroconf::sm_singleton_guard = 0;
56 CZeroconf* CZeroconf::smp_instance = 0;
57
58 CZeroconf::CZeroconf():mp_crit_sec(new CCriticalSection),m_started(false)
59 {
60 }
61
62 CZeroconf::~CZeroconf()
63 {
64   delete mp_crit_sec;
65 }
66
67 bool CZeroconf::PublishService(const std::string& fcr_identifier,
68                                const std::string& fcr_type,
69                                const std::string& fcr_name,
70                                unsigned int f_port,
71                                std::vector<std::pair<std::string, std::string> > txt /* = std::vector<std::pair<std::string, std::string> >() */)
72 {
73   CSingleLock lock(*mp_crit_sec);
74   CZeroconf::PublishInfo info = {fcr_type, fcr_name, f_port, txt};
75   std::pair<tServiceMap::const_iterator, bool> ret = m_service_map.insert(std::make_pair(fcr_identifier, info));
76   if(!ret.second) //identifier exists
77     return false;
78   if(m_started)
79     CJobManager::GetInstance().AddJob(new CPublish(fcr_identifier, info), NULL);
80
81   //not yet started, so its just queued
82   return true;
83 }
84
85 bool CZeroconf::RemoveService(const std::string& fcr_identifier)
86 {
87   CSingleLock lock(*mp_crit_sec);
88   tServiceMap::iterator it = m_service_map.find(fcr_identifier);
89   if(it == m_service_map.end())
90     return false;
91   m_service_map.erase(it);
92   if(m_started)
93     return doRemoveService(fcr_identifier);
94   else
95     return true;
96 }
97
98 bool CZeroconf::ForceReAnnounceService(const std::string& fcr_identifier)
99 {
100   if (HasService(fcr_identifier) && m_started)
101   {
102     return doForceReAnnounceService(fcr_identifier);
103   }
104   return false;
105 }
106
107 bool CZeroconf::HasService(const std::string& fcr_identifier) const
108 {
109   return (m_service_map.find(fcr_identifier) != m_service_map.end());
110 }
111
112 bool CZeroconf::Start()
113 {
114   CSingleLock lock(*mp_crit_sec);
115   if(!IsZCdaemonRunning())
116   {
117     CSettings::Get().SetBool("services.zeroconf", false);
118     if (CSettings::Get().GetBool("services.airplay"))
119       CSettings::Get().SetBool("services.airplay", false);
120     return false;
121   }
122   if(m_started)
123     return true;
124   m_started = true;
125
126   CJobManager::GetInstance().AddJob(new CPublish(m_service_map), NULL);
127   return true;
128 }
129
130 void CZeroconf::Stop()
131 {
132   CSingleLock lock(*mp_crit_sec);
133   if(!m_started)
134     return;
135   doStop();
136   m_started = false;
137 }
138
139 CZeroconf*  CZeroconf::GetInstance()
140 {
141   CAtomicSpinLock lock(sm_singleton_guard);
142   if(!smp_instance)
143   {
144 #ifndef HAS_ZEROCONF
145     smp_instance = new CZeroconfDummy;
146 #else
147 #if defined(TARGET_DARWIN)
148     smp_instance = new CZeroconfOSX;
149 #elif defined(HAS_AVAHI)
150     smp_instance  = new CZeroconfAvahi;
151 #elif defined(HAS_MDNS)
152     smp_instance  = new CZeroconfMDNS;
153 #endif
154 #endif
155   }
156   assert(smp_instance);
157   return smp_instance;
158 }
159
160 void CZeroconf::ReleaseInstance()
161 {
162   CAtomicSpinLock lock(sm_singleton_guard);
163   delete smp_instance;
164   smp_instance = 0;
165 }
166
167 CZeroconf::CPublish::CPublish(const std::string& fcr_identifier, const PublishInfo& pubinfo)
168 {
169   m_servmap.insert(std::make_pair(fcr_identifier, pubinfo));
170 }
171
172 CZeroconf::CPublish::CPublish(const tServiceMap& servmap) 
173   : m_servmap(servmap)
174 {
175 }
176
177 bool CZeroconf::CPublish::DoWork()
178 {
179   for(tServiceMap::const_iterator it = m_servmap.begin(); it != m_servmap.end(); ++it)
180     CZeroconf::GetInstance()->doPublishService(it->first, it->second.type, it->second.name, it->second.port, it->second.txt);
181
182   return true;
183 }