AnnoucementManager should take a Variant reference instead of pointer
[xbmc:xbmc-antiquated.git] / xbmc / lib / libjsonrpc / TCPServer.cpp
1 #include "TCPServer.h"
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <memory.h>
5 #include "JSONRPC.h"
6 #include "json/json.h"
7 #include "AnnouncementManager.h"
8 #include "log.h"
9 #include "Variant.h"
10 #include "SingleLock.h"
11
12 #ifdef _WIN32
13 extern "C" int inet_pton(int af, const char *src, void *dst);
14 #define close closesocket
15 #define SHUT_RDWR SD_BOTH
16 #endif
17
18 using namespace JSONRPC;
19 using namespace ANNOUNCEMENT;
20 //using namespace std; On VS2010, bind conflicts with std::bind
21 using namespace Json;
22
23 #define RECEIVEBUFFER 1024
24
25 CTCPServer *CTCPServer::ServerInstance = NULL;
26
27 bool CTCPServer::StartServer(int port, bool nonlocal)
28 {
29   StopServer(true);
30
31   ServerInstance = new CTCPServer(port, nonlocal);
32   if (ServerInstance->Initialize())
33   {
34     ServerInstance->Create();
35     return true;
36   }
37   else
38     return false;
39 }
40
41 void CTCPServer::StopServer(bool bWait)
42 {
43   if (ServerInstance)
44   {
45     ServerInstance->StopThread(bWait);
46     if (bWait)
47     {
48       delete ServerInstance;
49       ServerInstance = NULL;
50     }
51   }
52 }
53
54 CTCPServer::CTCPServer(int port, bool nonlocal)
55 {
56   m_port = port;
57   m_nonlocal = nonlocal;
58   m_ServerSocket = -1;
59 }
60
61 void CTCPServer::Process()
62 {
63   m_bStop = false;
64
65   while (!m_bStop)
66   {
67     int             max_fd = 0;
68     fd_set          rfds;
69     struct timeval  to     = {1, 0};
70     FD_ZERO(&rfds);
71
72     FD_SET(m_ServerSocket, &rfds);
73     max_fd = m_ServerSocket;
74
75     for (unsigned int i = 0; i < m_connections.size(); i++)
76     {
77       FD_SET(m_connections[i].m_socket, &rfds);
78       if (m_connections[i].m_socket > max_fd)
79         max_fd = m_connections[i].m_socket;
80     }
81
82     int res = select(max_fd+1, &rfds, NULL, NULL, &to);
83     if (res < 0)
84     {
85       CLog::Log(LOGERROR, "JSONRPC Server: Select failed");
86       Sleep(1000);
87       Initialize();
88     }
89     else if (res > 0)
90     {
91       for (int i = m_connections.size() - 1; i >= 0; i--)
92       {
93         int socket = m_connections[i].m_socket;
94         if (FD_ISSET(socket, &rfds))
95         {
96           char buffer[RECEIVEBUFFER] = {};
97           int  nread = 0;
98           nread = recv(socket, (char*)&buffer, RECEIVEBUFFER, 0);
99           if (nread > 0)
100           {
101             m_connections[i].PushBuffer(this, buffer, nread);
102           }
103           if (nread <= 0)
104           {
105             CLog::Log(LOGINFO, "JSONRPC Server: Disconnection detected");
106             m_connections[i].Disconnect();
107             m_connections.erase(m_connections.begin() + i);
108           }
109         }
110       }
111
112       if (FD_ISSET(m_ServerSocket, &rfds))
113       {
114         CLog::Log(LOGDEBUG, "JSONRPC Server: New connection detected");
115         CTCPClient newconnection;
116         newconnection.m_socket = accept(m_ServerSocket, &newconnection.m_cliaddr, &newconnection.m_addrlen);
117
118         if (newconnection.m_socket < 0)
119           CLog::Log(LOGERROR, "JSONRPC Server: Accept of new connection failed");
120         else
121         {
122           CLog::Log(LOGINFO, "JSONRPC Server: New connection added");
123           m_connections.push_back(newconnection);
124         }
125       }
126     }
127   }
128
129   Deinitialize();
130 }
131
132 bool CTCPServer::Download(const char *path, Json::Value *result)
133 {
134   return false;
135 }
136
137 int CTCPServer::GetCapabilities()
138 {
139   return Response | Announcing;
140 }
141
142 void CTCPServer::Announce(EAnnouncementFlag flag, const char *sender, const char *message, const CVariant &data)
143 {
144   Value root;
145   root["jsonrpc"] = "2.0";
146   root["method"]  = "Announcement";
147   root["params"]["sender"] = sender;
148   root["params"]["message"] = message;
149   if (!data.isNull())
150     data.toJsonValue(root["params"]["data"]);
151
152   StyledWriter writer;
153   std::string str = writer.write(root);
154
155   for (unsigned int i = 0; i < m_connections.size(); i++)
156   {
157     unsigned int sent = 0;
158     do
159     {
160       CSingleLock lock (m_connections[i].m_critSection);
161       sent += send(m_connections[i].m_socket, str.c_str(), str.size() - sent, sent);
162     } while (sent < str.size());
163   }
164 }
165
166 bool CTCPServer::Initialize()
167 {
168   Deinitialize();
169
170   struct sockaddr_in myaddr;
171
172   myaddr.sin_family = AF_INET;
173   myaddr.sin_port = htons(m_port);
174
175   if (m_nonlocal)
176     myaddr.sin_addr.s_addr = INADDR_ANY;
177   else
178     inet_pton(AF_INET, "127.0.0.1", &myaddr.sin_addr.s_addr);
179
180   m_ServerSocket = socket(PF_INET, SOCK_STREAM, 0);
181
182   if (m_ServerSocket < 0)
183   {
184 #ifdef _WIN32
185     int ierr = WSAGetLastError();
186     CLog::Log(LOGERROR, "JSONRPC Server: Failed to create serversocket %d", ierr);
187     // hack for broken third party libs
188     if(ierr == WSANOTINITIALISED)
189     {
190       WSADATA wd;
191       if (WSAStartup(MAKEWORD(2,2), &wd) != 0)
192         CLog::Log(LOGERROR, "JSONRPC Server: WSAStartup failed");
193     }
194 #else
195     CLog::Log(LOGERROR, "JSONRPC Server: Failed to create serversocket");
196 #endif
197     return false;
198   }
199
200   if (bind(m_ServerSocket, (struct sockaddr*)&myaddr, sizeof myaddr) < 0)
201   {
202     CLog::Log(LOGERROR, "JSONRPC Server: Failed to bind serversocket");
203     close(m_ServerSocket);
204     return false;
205   }
206   
207   if (listen(m_ServerSocket, 10) < 0)
208   {
209     CLog::Log(LOGERROR, "JSONRPC Server: Failed to set listen");
210     close(m_ServerSocket);
211     return false;
212   }
213
214   CAnnouncementManager::AddAnnouncer(this);
215
216   CLog::Log(LOGINFO, "JSONRPC Server: Successfully initialized");
217   return true;
218 }
219
220 void CTCPServer::Deinitialize()
221 {
222   for (unsigned int i = 0; i < m_connections.size(); i++)
223     m_connections[i].Disconnect();
224
225   m_connections.clear();
226
227   if (m_ServerSocket > 0)
228   {
229     shutdown(m_ServerSocket, SHUT_RDWR);
230     close(m_ServerSocket);
231     m_ServerSocket = -1;
232   }
233
234   CAnnouncementManager::RemoveAnnouncer(this);
235 }
236
237 CTCPServer::CTCPClient::CTCPClient()
238 {
239   m_announcementflags = 0;
240   m_socket = -1;
241   m_beginBrackets = 0;
242   m_endBrackets = 0;
243
244   m_addrlen = sizeof(struct sockaddr);
245 }
246
247 CTCPServer::CTCPClient::CTCPClient(const CTCPClient& client)
248 {
249   Copy(client);
250 }
251
252 CTCPServer::CTCPClient& CTCPServer::CTCPClient::operator=(const CTCPClient& client)
253 {
254   Copy(client);
255   return *this;
256 }
257
258 int CTCPServer::CTCPClient::GetPermissionFlags()
259 {
260   return OPERATION_PERMISSION_ALL;
261 }
262
263 int CTCPServer::CTCPClient::GetAnnouncementFlags()
264 {
265   return m_announcementflags;
266 }
267
268 bool CTCPServer::CTCPClient::SetAnnouncementFlags(int flags)
269 {
270   m_announcementflags = flags;
271   return true;
272 }
273
274 void CTCPServer::CTCPClient::PushBuffer(CTCPServer *host, const char *buffer, int length)
275 {
276   for (int i = 0; i < length; i++)
277   {
278     char c = buffer[i];
279     m_buffer.push_back(c);
280     if (c == '{')
281       m_beginBrackets++;
282     else if (c == '}')
283       m_endBrackets++;
284     if (m_beginBrackets > 0 && m_endBrackets > 0 && m_beginBrackets == m_endBrackets)
285     {
286       std::string line = CJSONRPC::MethodCall(m_buffer, host, this);
287       CSingleLock lock (m_critSection);
288       send(m_socket, line.c_str(), line.size(), 0);
289       m_beginBrackets = m_endBrackets = 0;
290       m_buffer.clear();
291     }
292   }
293 }
294
295 void CTCPServer::CTCPClient::Disconnect()
296 {
297   if (m_socket > 0)
298   {
299     CSingleLock lock (m_critSection);
300     shutdown(m_socket, SHUT_RDWR);
301     close(m_socket);
302     m_socket = -1;
303   }
304 }
305
306 void CTCPServer::CTCPClient::Copy(const CTCPClient& client)
307 {
308   m_socket            = client.m_socket;
309   m_cliaddr           = client.m_cliaddr;
310   m_addrlen           = client.m_addrlen;
311   m_announcementflags = client.m_announcementflags;
312   m_beginBrackets     = client.m_beginBrackets;
313   m_endBrackets       = client.m_endBrackets;
314   m_buffer            = client.m_buffer;
315 }
316