Removed Adaptor::Get() dependency from TriggerEventFactory
[platform/core/uifw/dali-adaptor.git] / dali / internal / network / common / network-performance-server.cpp
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/network/common/network-performance-server.h>
20
21
22 // INTERNAL INCLUDES
23 #include <dali/internal/system/common/performance-marker.h>
24
25 namespace Dali
26 {
27
28 namespace Internal
29 {
30
31 namespace Adaptor
32 {
33
34 namespace // un-named namespace
35 {
36 const unsigned int SERVER_PORT = 3031;
37 const unsigned int MAXIMUM_PORTS_TO_TRY = 10; ///< if port in use, try up to SERVER_PORT + 10
38 const unsigned int CONNECTION_BACKLOG = 2;   ///<  maximum length of the queue of pending connections.
39 const unsigned int SOCKET_READ_BUFFER_SIZE = 4096;
40 typedef Vector< NetworkPerformanceClient*> ClientList;
41
42 /**
43  * POD passed to client thread on startup
44  */
45 struct ClientThreadInfo
46 {
47   NetworkPerformanceServer* server;
48   NetworkPerformanceClient* client;
49 };
50 }
51
52 NetworkPerformanceServer::NetworkPerformanceServer( AdaptorInternalServices& adaptorServices,
53                                                     const EnvironmentOptions& logOptions )
54 : mSocketFactory( adaptorServices.GetSocketFactoryInterface() ),
55   mLogOptions( logOptions ),
56   mServerThread( 0 ),
57   mListeningSocket( NULL ),
58   mClientUniqueId( 0 ),
59   mClientCount( 0 ),
60   mLogFunctionInstalled( false )
61 {
62 }
63
64 NetworkPerformanceServer::~NetworkPerformanceServer()
65 {
66   Stop();
67
68   if( mLogFunctionInstalled )
69   {
70     mLogOptions.UnInstallLogFunction();
71   }
72 }
73
74 void NetworkPerformanceServer::Start()
75 {
76   // start a thread to listen for incoming connection requests
77   if (! mServerThread )
78   {
79     if( mListeningSocket )
80     {
81       mSocketFactory.DestroySocket( mListeningSocket );
82     }
83     mListeningSocket = mSocketFactory.NewSocket( SocketInterface::TCP);
84     mListeningSocket->ReuseAddress( true );
85
86     bool bound = false;
87     unsigned int basePort = 0;
88
89     // try a small range of ports, so if multiple Dali apps are running you can select
90     // which one to connect to
91     while( !bound && ( basePort <  MAXIMUM_PORTS_TO_TRY ))
92     {
93       bound = mListeningSocket->Bind( SERVER_PORT + basePort );
94       if( !bound )
95       {
96         basePort++;
97       }
98     }
99     if(!bound )
100     {
101       DALI_LOG_ERROR("Failed to bind to a port \n");
102       return;
103     }
104
105     mListeningSocket->Listen( CONNECTION_BACKLOG );
106
107     // start a thread which will block waiting for new connections
108     int error = pthread_create( &mServerThread, NULL, ConnectionListenerFunc, this );
109     DALI_ASSERT_ALWAYS( !error && "pthread create failed" );
110
111     Dali::Integration::Log::LogMessage(Integration::Log::DebugInfo, "~~~ NetworkPerformanceServer started on port %d ~~~ \n",  SERVER_PORT + basePort);
112
113   }
114 }
115 void NetworkPerformanceServer::Stop()
116 {
117   if( !mServerThread )
118   {
119     return;
120   }
121
122   if( mListeningSocket )
123   {
124     // close the server thread to prevent any new connections
125     mListeningSocket->ExitSelect();
126   }
127
128   // wait for the thread to exit.
129   void* exitValue;
130   pthread_join( mServerThread, &exitValue );
131
132   if( mListeningSocket )
133   {
134     // close the socket
135     mListeningSocket->CloseSocket();
136   }
137
138   mSocketFactory.DestroySocket( mListeningSocket );
139
140   mListeningSocket = NULL;
141
142   // this will tell all client threads to quit
143   StopClients();
144
145 }
146
147 bool NetworkPerformanceServer::IsRunning() const
148 {
149   if (mServerThread )
150   {
151     return true;
152   }
153   return false;
154 }
155
156 void NetworkPerformanceServer::ClientThread( NetworkPerformanceClient* client )
157 {
158   mClientCount++;
159
160   SocketInterface& socket( client->GetSocket() );
161
162   for( ;; )
163   {
164     SocketInterface::SelectReturn ret = socket.Select();
165
166     if( ret == SocketInterface::DATA_AVAILABLE )
167     {
168      // Read
169       char buffer[ SOCKET_READ_BUFFER_SIZE ];
170       unsigned int  bytesRead;
171
172       bool ok  = socket.Read( buffer, sizeof( buffer ) , bytesRead);
173       if( ok && ( bytesRead > 0) )
174       {
175         client->ProcessCommand( buffer, bytesRead );
176       }
177       else   // if bytesRead == 0, then client closed connection, if ok == false then an error
178       {
179         DeleteClient( client );
180         return;
181       }
182     }
183     else // ret == QUIT or ERROR
184     {
185       DeleteClient( client);
186       return;
187     }
188   }
189 }
190
191 void NetworkPerformanceServer::ConnectionListener()
192 {
193   // install Dali logging function for this thread
194   if( !mLogFunctionInstalled )
195   {
196     mLogOptions.InstallLogFunction();
197     mLogFunctionInstalled = true;
198   }
199
200   for( ;; )
201   {
202     // this will block, waiting for a client to connect
203     // or for mListeningSocket->ExitSelect() to be called
204
205     SocketInterface::SelectReturn ret = mListeningSocket->Select();
206
207     if( ret == SocketInterface::DATA_AVAILABLE )
208     {
209       SocketInterface* clientSocket = mListeningSocket->Accept();
210
211       // new connection made, spawn a thread to handle it
212       pthread_t* clientThread = new pthread_t();
213
214       NetworkPerformanceClient* client = AddClient( clientSocket, clientThread );
215
216       ClientThreadInfo* info = new ClientThreadInfo;
217       info->client = client;
218       info->server = this;
219
220       int error = pthread_create( clientThread, NULL, ClientThreadFunc, info );
221       DALI_ASSERT_ALWAYS( !error && "pthread create failed" );
222
223     }
224     else // ret == SocketInterface::QUIT or SocketInterface::ERROR
225     {
226       return;
227     }
228   }
229 }
230
231 void* NetworkPerformanceServer::ClientThreadFunc( void* data )
232 {
233   ClientThreadInfo* info = static_cast<ClientThreadInfo*>( data );
234   info->server->ClientThread( info->client );
235   delete info;
236   return NULL;
237 }
238
239 NetworkPerformanceClient* NetworkPerformanceServer::AddClient( SocketInterface* clientSocket, pthread_t* clientThread )
240 {
241   // This function is only called from the listening thread
242   NetworkPerformanceClient* client= new NetworkPerformanceClient( clientThread,
243                                                                   clientSocket,
244                                                                   mClientUniqueId++,
245                                                                   *this,
246                                                                   mSocketFactory);
247
248   // protect the mClients list which can be accessed from multiple threads.
249   Mutex::ScopedLock lock( mClientListMutex );
250
251   mClients.PushBack( client );
252
253   return client;
254 }
255
256 void NetworkPerformanceServer::DeleteClient( NetworkPerformanceClient* client )
257 {
258   // protect the mClients list while modifying
259   Mutex::ScopedLock lock( mClientListMutex );
260
261   // remove from the list, and delete it
262   for( ClientList::Iterator iter = mClients.Begin(); iter != mClients.End() ; ++iter )
263   {
264     if( (*iter) == client )
265     {
266       mClients.Erase( iter );
267       delete client;
268
269       // if there server is shutting down, it waits for client count to hit zero
270       mClientCount--;
271
272       return;
273     }
274   }
275 }
276
277 void NetworkPerformanceServer::SendData( const char* const data, unsigned int bufferSizeInBytes,unsigned int clientId )
278 {
279   if( ! mClientCount )
280   {
281     return;
282   }
283
284   // prevent clients been added / deleted while transmiting data
285   Mutex::ScopedLock lock( mClientListMutex );
286
287   for( ClientList::Iterator iter = mClients.Begin(); iter != mClients.End() ; ++iter )
288   {
289     NetworkPerformanceClient* client = (*iter);
290     if( client->GetId() == clientId )
291     {
292       client->WriteSocket(data ,bufferSizeInBytes);
293       return;
294     }
295   }
296 }
297
298 void NetworkPerformanceServer::TransmitMarker( const PerformanceMarker& marker, const char* const description )
299 {
300   if( ! IsRunning() )
301   {
302     return;
303   }
304   // prevent clients been added / deleted while transmiting data
305   Mutex::ScopedLock lock( mClientListMutex );
306
307   for( ClientList::Iterator iter = mClients.Begin(); iter != mClients.End() ; ++iter )
308   {
309     NetworkPerformanceClient* client = (*iter);
310     client->TransmitMarker( marker, description );
311   }
312 }
313
314
315 void NetworkPerformanceServer::StopClients()
316 {
317   // prevent clients been added / deleted while stopping all clients
318   Mutex::ScopedLock lock( mClientListMutex );
319
320   for( ClientList::Iterator iter = mClients.Begin(); iter != mClients.End() ; ++iter )
321   {
322     NetworkPerformanceClient* client = (*iter);
323     // stop the client from waiting for new commands, and exit from it's thread
324     client->ExitSelect();
325   }
326 }
327
328 } // namespace Internal
329
330 } // namespace Adaptor
331
332 } // namespace Dali