2 * Copyright (C) 2005-2013 Team XBMC
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)
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.
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/>.
23 #ifdef HAS_EVENT_SERVER
25 #include "EventServer.h"
26 #include "EventPacket.h"
27 #include "EventClient.h"
29 #include "threads/CriticalSection.h"
30 #include "Application.h"
31 #include "interfaces/builtins/Builtins.h"
32 #include "input/ButtonTranslator.h"
33 #include "threads/SingleLock.h"
35 #include "guilib/GUIAudioManager.h"
36 #include "input/Key.h"
37 #include "utils/log.h"
38 #include "utils/SystemInfo.h"
44 using namespace EVENTSERVER
;
45 using namespace EVENTPACKET
;
46 using namespace EVENTCLIENT
;
47 using namespace SOCKETS
;
49 /************************************************************************/
51 /************************************************************************/
52 CEventServer
* CEventServer::m_pInstance
= NULL
;
53 CEventServer::CEventServer() : CThread("EventServer")
56 m_pPacketBuffer
= NULL
;
59 m_bRefreshSettings
= false;
61 // default timeout in ms for receiving a single packet
62 m_iListenTimeout
= 1000;
65 void CEventServer::RemoveInstance()
74 CEventServer
* CEventServer::GetInstance()
78 m_pInstance
= new CEventServer();
83 void CEventServer::StartServer()
85 CSingleLock
lock(m_critSection
);
90 m_iPort
= CSettings::GetInstance().GetInt(CSettings::SETTING_SERVICES_ESPORT
);
91 assert(m_iPort
<= 65535 && m_iPort
>= 1);
94 m_iMaxClients
= CSettings::GetInstance().GetInt(CSettings::SETTING_SERVICES_ESMAXCLIENTS
);
95 if (m_iMaxClients
< 0)
97 CLog::Log(LOGERROR
, "ES: Invalid maximum number of clients specified %d", m_iMaxClients
);
104 void CEventServer::StopServer(bool bWait
)
106 CZeroconf::GetInstance()->RemoveService("services.eventserver");
110 void CEventServer::Cleanup()
121 free(m_pPacketBuffer
);
122 m_pPacketBuffer
= NULL
;
124 CSingleLock
lock(m_critSection
);
126 std::map
<unsigned long, CEventClient
*>::iterator iter
= m_clients
.begin();
127 while (iter
!= m_clients
.end())
133 m_clients
.erase(iter
);
134 iter
= m_clients
.begin();
138 int CEventServer::GetNumberOfClients()
140 CSingleLock
lock(m_critSection
);
141 return m_clients
.size();
144 void CEventServer::Process()
154 void CEventServer::Run()
156 CSocketListener listener
;
159 CLog::Log(LOGNOTICE
, "ES: Starting UDP Event server on port %d", m_iPort
);
163 // create socket and initialize buffer
164 m_pSocket
= CSocketFactory::CreateUDPSocket();
167 CLog::Log(LOGERROR
, "ES: Could not create socket, aborting!");
170 m_pPacketBuffer
= (unsigned char *)malloc(PACKET_SIZE
);
172 if (!m_pPacketBuffer
)
174 CLog::Log(LOGERROR
, "ES: Out of memory, could not allocate packet buffer");
178 // bind to IP and start listening on port
179 int port_range
= CSettings::GetInstance().GetInt(CSettings::SETTING_SERVICES_ESPORTRANGE
);
180 if (port_range
< 1 || port_range
> 100)
182 CLog::Log(LOGERROR
, "ES: Invalid port range specified %d, defaulting to 10", port_range
);
185 if (!m_pSocket
->Bind(!CSettings::GetInstance().GetBool(CSettings::SETTING_SERVICES_ESALLINTERFACES
), m_iPort
, port_range
))
187 CLog::Log(LOGERROR
, "ES: Could not listen on port %d", m_iPort
);
192 std::vector
<std::pair
<std::string
, std::string
> > txt
;
193 CZeroconf::GetInstance()->PublishService("servers.eventserver",
195 CSysInfo::GetDeviceName(),
199 // add our socket to the 'select' listener
200 listener
.AddSocket(m_pSocket
);
208 // start listening until we timeout
209 if (listener
.Listen(m_iListenTimeout
))
212 if ((packetSize
= m_pSocket
->Read(addr
, PACKET_SIZE
, (void *)m_pPacketBuffer
)) > -1)
214 ProcessPacket(addr
, packetSize
);
220 CLog::Log(LOGERROR
, "ES: Exception caught while listening for socket");
224 // process events and queue the necessary actions and button codes
227 // refresh client list
231 // BroadcastBeacon();
234 CLog::Log(LOGNOTICE
, "ES: UDP Event server stopped");
239 void CEventServer::ProcessPacket(CAddress
& addr
, int pSize
)
241 // check packet validity
242 CEventPacket
* packet
= new CEventPacket(pSize
, m_pPacketBuffer
);
245 CLog::Log(LOGERROR
, "ES: Out of memory, cannot accept packet");
249 unsigned int clientToken
;
251 if (!packet
->IsValid())
253 CLog::Log(LOGDEBUG
, "ES: Received invalid packet");
258 clientToken
= packet
->ClientToken();
260 clientToken
= addr
.ULong(); // use IP if packet doesn't have a token
262 CSingleLock
lock(m_critSection
);
264 // first check if we have a client for this address
265 std::map
<unsigned long, CEventClient
*>::iterator iter
= m_clients
.find(clientToken
);
267 if ( iter
== m_clients
.end() )
269 if ( m_clients
.size() >= (unsigned int)m_iMaxClients
)
271 CLog::Log(LOGWARNING
, "ES: Cannot accept any more clients, maximum client count reached");
277 CEventClient
* client
= new CEventClient ( addr
);
280 CLog::Log(LOGERROR
, "ES: Out of memory, cannot accept new client connection");
285 m_clients
[clientToken
] = client
;
287 m_clients
[clientToken
]->AddPacket(packet
);
290 void CEventServer::RefreshClients()
292 CSingleLock
lock(m_critSection
);
293 std::map
<unsigned long, CEventClient
*>::iterator iter
= m_clients
.begin();
295 while ( iter
!= m_clients
.end() )
297 if (! (iter
->second
->Alive()))
299 CLog::Log(LOGNOTICE
, "ES: Client %s from %s timed out", iter
->second
->Name().c_str(),
300 iter
->second
->Address().Address());
302 m_clients
.erase(iter
);
303 iter
= m_clients
.begin();
307 if (m_bRefreshSettings
)
309 iter
->second
->RefreshSettings();
314 m_bRefreshSettings
= false;
317 void CEventServer::ProcessEvents()
319 CSingleLock
lock(m_critSection
);
320 std::map
<unsigned long, CEventClient
*>::iterator iter
= m_clients
.begin();
322 while (iter
!= m_clients
.end())
324 iter
->second
->ProcessEvents();
329 bool CEventServer::ExecuteNextAction()
331 CSingleLock
lock(m_critSection
);
333 CEventAction actionEvent
;
334 std::map
<unsigned long, CEventClient
*>::iterator iter
= m_clients
.begin();
336 while (iter
!= m_clients
.end())
338 if (iter
->second
->GetNextAction(actionEvent
))
340 // Leave critical section before processing action
342 switch(actionEvent
.actionType
)
344 case AT_EXEC_BUILTIN
:
345 CBuiltins::GetInstance().Execute(actionEvent
.actionName
);
351 CButtonTranslator::TranslateActionString(actionEvent
.actionName
.c_str(), actionID
);
352 CAction
action(actionID
, 1.0f
, 0.0f
, actionEvent
.actionName
);
353 g_audioManager
.PlayActionSound(action
);
354 g_application
.OnAction(action
);
366 unsigned int CEventServer::GetButtonCode(std::string
& strMapName
, bool& isAxis
, float& fAmount
, bool &isJoystick
)
368 CSingleLock
lock(m_critSection
);
369 std::map
<unsigned long, CEventClient
*>::iterator iter
= m_clients
.begin();
370 unsigned int bcode
= 0;
372 while (iter
!= m_clients
.end())
374 bcode
= iter
->second
->GetButtonCode(strMapName
, isAxis
, fAmount
, isJoystick
);
382 bool CEventServer::GetMousePos(float &x
, float &y
)
384 CSingleLock
lock(m_critSection
);
385 std::map
<unsigned long, CEventClient
*>::iterator iter
= m_clients
.begin();
387 while (iter
!= m_clients
.end())
389 if (iter
->second
->GetMousePos(x
, y
))
396 #endif // HAS_EVENT_SERVER