Dali 3D User Interface Engine
network-performance-server.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 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
20 
21 
22 // INTERNAL INCLUDES
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;
38 const unsigned int CONNECTION_BACKLOG = 2;
39 const unsigned int SOCKET_READ_BUFFER_SIZE = 4096;
41 
46 {
49 };
50 }
51 
53  const EnvironmentOptions& logOptions )
54 : mTriggerEventFactory( adaptorServices.GetTriggerEventFactoryInterface() ),
55  mSocketFactory( adaptorServices.GetSocketFactoryInterface() ),
56  mLogOptions( logOptions ),
57  mServerThread( 0 ),
58  mListeningSocket( NULL ),
59  mClientUniqueId( 0 ),
60  mClientCount( 0 ),
61  mLogFunctionInstalled( false )
62 {
63 }
64 
66 {
67  Stop();
68 
70  {
72  }
73 }
74 
76 {
77  // start a thread to listen for incoming connection requests
78  if (! mServerThread )
79  {
80  if( mListeningSocket )
81  {
83  }
86 
87  bool bound = false;
88  unsigned int basePort = 0;
89 
90  // try a small range of ports, so if multiple Dali apps are running you can select
91  // which one to connect to
92  while( !bound && ( basePort < MAXIMUM_PORTS_TO_TRY ))
93  {
94  bound = mListeningSocket->Bind( SERVER_PORT + basePort );
95  if( !bound )
96  {
97  basePort++;
98  }
99  }
100  if(!bound )
101  {
102  DALI_LOG_ERROR("Failed to bind to a port \n");
103  return;
104  }
105 
107 
108  // start a thread which will block waiting for new connections
109  int error = pthread_create( &mServerThread, NULL, ConnectionListenerFunc, this );
110  DALI_ASSERT_ALWAYS( !error && "pthread create failed" );
111 
112  Dali::Integration::Log::LogMessage(Integration::Log::DebugInfo, "~~~ NetworkPerformanceServer started on port %d ~~~ \n", SERVER_PORT + basePort);
113 
114  }
115 }
117 {
118  if( !mServerThread )
119  {
120  return;
121  }
122  // close the server thread to prevent any new connections
124 
125  // wait for the thread to exit.
126  void* exitValue;
127  pthread_join( mServerThread, &exitValue );
128 
129  // close the socket
131 
133 
134  mListeningSocket = NULL;
135 
136  // this will tell all client threads to quit
137  StopClients();
138 
139 }
140 
142 {
143  if (mServerThread )
144  {
145  return true;
146  }
147  return false;
148 }
149 
151 {
152  mClientCount++;
153 
154  SocketInterface& socket( client->GetSocket() );
155 
156  for( ;; )
157  {
158  SocketInterface::SelectReturn ret = socket.Select();
159 
161  {
162  // Read
163  char buffer[ SOCKET_READ_BUFFER_SIZE ];
164  unsigned int bytesRead;
165 
166  bool ok = socket.Read( buffer, sizeof( buffer ) , bytesRead);
167  if( ok && ( bytesRead > 0) )
168  {
169  client->ProcessCommand( buffer, bytesRead );
170  }
171  else // if bytesRead == 0, then client closed connection, if ok == false then an error
172  {
173  DeleteClient( client );
174  return;
175  }
176  }
177  else // ret == QUIT or ERROR
178  {
179  DeleteClient( client);
180  return;
181  }
182  }
183 }
184 
186 {
187  // install Dali logging function for this thread
188  if( !mLogFunctionInstalled )
189  {
191  mLogFunctionInstalled = true;
192  }
193 
194  for( ;; )
195  {
196  // this will block, waiting for a client to connect
197  // or for mListeningSocket->ExitSelect() to be called
198 
200 
202  {
203  SocketInterface* clientSocket = mListeningSocket->Accept();
204 
205  // new connection made, spawn a thread to handle it
206  pthread_t* clientThread = new pthread_t();
207 
208  NetworkPerformanceClient* client = AddClient( clientSocket, clientThread );
209 
210  ClientThreadInfo* info = new ClientThreadInfo;
211  info->client = client;
212  info->server = this;
213 
214  int error = pthread_create( clientThread, NULL, ClientThreadFunc, info );
215  DALI_ASSERT_ALWAYS( !error && "pthread create failed" );
216 
217  }
218  else // ret == SocketInterface::QUIT or SocketInterface::ERROR
219  {
220  return;
221  }
222  }
223 }
224 
226 {
227  ClientThreadInfo* info = static_cast<ClientThreadInfo*>( data );
228  info->server->ClientThread( info->client );
229  delete info;
230  return NULL;
231 }
232 
234 {
235  // This function is only called from the listening thread
236  NetworkPerformanceClient* client= new NetworkPerformanceClient( clientThread,
237  clientSocket,
238  mClientUniqueId++,
240  *this,
242 
243  // protect the mClients list which can be accessed from multiple threads.
245 
246  mClients.PushBack( client );
247 
248  return client;
249 }
250 
252 {
253  // protect the mClients list while modifying
255 
256  // remove from the list, and delete it
257  for( ClientList::Iterator iter = mClients.Begin(); iter != mClients.End() ; ++iter )
258  {
259  if( (*iter) == client )
260  {
261  mClients.Erase( iter );
262  delete client;
263 
264  // if there server is shutting down, it waits for client count to hit zero
265  mClientCount--;
266 
267  return;
268  }
269  }
270 }
271 
272 void NetworkPerformanceServer::SendData( const char* const data, unsigned int bufferSizeInBytes,unsigned int clientId )
273 {
274  if( ! mClientCount )
275  {
276  return;
277  }
278 
279  // prevent clients been added / deleted while transmiting data
281 
282  for( ClientList::Iterator iter = mClients.Begin(); iter != mClients.End() ; ++iter )
283  {
284  NetworkPerformanceClient* client = (*iter);
285  if( client->GetId() == clientId )
286  {
287  client->WriteSocket(data ,bufferSizeInBytes);
288  return;
289  }
290  }
291 }
292 
293 void NetworkPerformanceServer::TransmitMarker( const PerformanceMarker& marker, const char* const description )
294 {
295  if( ! IsRunning() )
296  {
297  return;
298  }
299  // prevent clients been added / deleted while transmiting data
301 
302  for( ClientList::Iterator iter = mClients.Begin(); iter != mClients.End() ; ++iter )
303  {
304  NetworkPerformanceClient* client = (*iter);
305  client->TransmitMarker( marker, description );
306  }
307 }
308 
309 
311 {
312  // prevent clients been added / deleted while stopping all clients
314 
315  for( ClientList::Iterator iter = mClients.Begin(); iter != mClients.End() ; ++iter )
316  {
317  NetworkPerformanceClient* client = (*iter);
318  // stop the client from waiting for new commands, and exit from it's thread
319  client->ExitSelect();
320 
321  void* exitValue;
322  pthread_t* thread = client->GetThread();
323  pthread_join( *thread, &exitValue );
324  delete thread;
325 
326  }
327 }
328 
329 } // namespace Internal
330 
331 } // namespace Adaptor
332 
333 } // namespace Dali
Dali Docs Home
Read more about Dali