Prevented buffer clipping in network server
[platform/core/uifw/dali-adaptor.git] / dali / internal / network / common / network-performance-client.cpp
1 /*
2  * Copyright (c) 2022 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-client.h>
20
21 // EXTERNAL INCLUDES
22 #include <stdio.h>
23 #include <iostream>
24 #include <string>
25
26 // INTERNAL INCLUDES
27 #include <dali/internal/network/common/automation.h>
28 #include <dali/internal/network/common/network-performance-protocol.h>
29 #include <dali/internal/network/common/socket-interface.h>
30
31 namespace Dali
32 {
33 namespace Internal
34 {
35 namespace Adaptor
36 {
37 namespace
38 {
39 const float MICROSECONDS_TO_SECOND = 1e-6;
40 const char  UNKNOWN_CMD[]          = "Command or parameter invalid, type help for list of commands\n";
41
42 /**
43  * helper class to store data along with the automation callback.
44  */
45 class AutomationCallback : public CallbackBase
46 {
47 public:
48   /**
49    * instead of using templates, or having different callback classes for each callback
50    * we use a command id that decides which static function to call on the Automation class.
51    */
52   enum CommandId
53   {
54     UNKNOWN_COMMAND,
55     SET_PROPERTY,
56     CUSTOM_COMMAND,
57     DUMP_SCENE
58   };
59
60   AutomationCallback(unsigned int clientId, ClientSendDataInterface& sendDataInterface)
61   : CallbackBase(reinterpret_cast<void*>(this),
62                  NULL, // we get the dispatcher to call function directly
63                  reinterpret_cast<CallbackBase::Dispatcher>(&AutomationCallback::Dispatcher)),
64     mSendDataInterface(sendDataInterface),
65     mCommandId(UNKNOWN_COMMAND),
66     mClientId(clientId)
67   {
68   }
69
70   void AssignSetPropertyCommand(std::string setPropertyCommand)
71   {
72     mCommandId     = SET_PROPERTY;
73     mCommandString = setPropertyCommand;
74   }
75
76   void AssignDumpSceneCommand()
77   {
78     mCommandId = DUMP_SCENE;
79   }
80
81   void AssignCustomCommand(std::string&& customCommand)
82   {
83     mCommandId     = CUSTOM_COMMAND;
84     mCommandString = std::move(customCommand);
85   }
86
87   void RunCallback()
88   {
89     switch(mCommandId)
90     {
91       case SET_PROPERTY:
92       {
93         Automation::SetProperty(mCommandString);
94         break;
95       }
96       case DUMP_SCENE:
97       {
98         Automation::DumpScene(mClientId, &mSendDataInterface);
99         break;
100       }
101       case CUSTOM_COMMAND:
102       {
103         Automation::SetCustomCommand(mCommandString);
104         break;
105       }
106       default:
107       {
108         DALI_ASSERT_DEBUG(0 && "Unknown command");
109         break;
110       }
111     }
112   }
113   static void Dispatcher(CallbackBase& base)
114   {
115     AutomationCallback& automationCallback(static_cast<AutomationCallback&>(base));
116     automationCallback.RunCallback();
117   }
118
119 private:
120   std::string              mCommandString;     ///< command string for property or custom command
121   ClientSendDataInterface& mSendDataInterface; ///< Abstract client send data interface
122   CommandId                mCommandId;         ///< command id
123   const unsigned int       mClientId;          ///< client id
124 };
125
126 /**
127  * @brief Helper to ensure the AutomationCallback method we want is called in the main thread
128  */
129 template<typename T>
130 void TriggerOnMainThread(unsigned int clientId, ClientSendDataInterface& sendDataInterface, T&& lambda)
131 {
132   // this needs to be run on the main thread, use the trigger event....
133   AutomationCallback* callback = new AutomationCallback(clientId, sendDataInterface);
134   lambda(callback);
135
136   // create a trigger event that automatically deletes itself after the callback has run in the main thread
137   TriggerEventInterface* interface = TriggerEventFactory::CreateTriggerEvent(callback, TriggerEventInterface::DELETE_AFTER_TRIGGER);
138
139   // asynchronous call, the call back will be run sometime later on the main thread
140   interface->Trigger();
141 }
142
143 } // unnamed namespace
144
145 NetworkPerformanceClient::NetworkPerformanceClient(pthread_t*               thread,
146                                                    SocketInterface*         socket,
147                                                    unsigned int             clientId,
148                                                    ClientSendDataInterface& sendDataInterface,
149                                                    SocketFactoryInterface&  socketFactory)
150 : mThread(thread),
151   mSocket(socket),
152   mMarkerBitmask(PerformanceMarker::FILTERING_DISABLED),
153   mSendDataInterface(sendDataInterface),
154   mSocketFactoryInterface(socketFactory),
155   mClientId(clientId),
156   mConsoleClient(false)
157 {
158 }
159
160 NetworkPerformanceClient::~NetworkPerformanceClient()
161 {
162   if(mSocket->SocketIsOpen())
163   {
164     mSocket->CloseSocket();
165   }
166   mSocketFactoryInterface.DestroySocket(mSocket);
167 }
168
169 unsigned int NetworkPerformanceClient::GetId() const
170 {
171   return mClientId;
172 }
173
174 SocketInterface& NetworkPerformanceClient::GetSocket()
175 {
176   return *mSocket;
177 }
178
179 bool NetworkPerformanceClient::WriteSocket(const void* buffer, unsigned int bufferSizeInBytes)
180 {
181   return mSocket->Write(buffer, bufferSizeInBytes);
182 }
183
184 bool NetworkPerformanceClient::TransmitMarker(const PerformanceMarker& marker, const char* const description)
185 {
186   if(!marker.IsFilterEnabled(mMarkerBitmask))
187   {
188     return true;
189   }
190   if(mConsoleClient)
191   {
192     // write out the time stamp
193     char   *buffer;
194     double usec = marker.GetTimeStamp().microseconds;
195     int    size = asprintf(&buffer, "%.6f (seconds), %s\n", usec * MICROSECONDS_TO_SECOND, description);
196     auto retVal = mSocket->Write(buffer, size);
197     free(buffer);
198     return retVal;
199   }
200
201   // todo serialize the data
202   return false;
203 }
204
205 void NetworkPerformanceClient::ExitSelect()
206 {
207   mSocket->ExitSelect();
208 }
209
210 pthread_t* NetworkPerformanceClient::GetThread()
211 {
212   return mThread;
213 }
214
215 void NetworkPerformanceClient::ProcessCommand(char* buffer, unsigned int bufferSizeInBytes)
216 {
217   // if connected via console, then strip off the carriage return, and switch to console mode
218   if(buffer[bufferSizeInBytes - 1] == '\n')
219   {
220     buffer[bufferSizeInBytes - 1] = 0;
221     mConsoleClient                = true;
222   }
223   unsigned int                   param(0);
224   std::string                    stringParam;
225   PerformanceProtocol::CommandId commandId(PerformanceProtocol::UNKNOWN_COMMAND);
226
227   bool ok = PerformanceProtocol::GetCommandId(buffer, bufferSizeInBytes, commandId, param, stringParam);
228   if(!ok)
229   {
230     WriteSocket(UNKNOWN_CMD, sizeof(UNKNOWN_CMD));
231     return;
232   }
233   std::string response;
234
235   switch(commandId)
236   {
237     case PerformanceProtocol::HELP_MESSAGE:
238     {
239       response = PerformanceProtocol::GetHelpMessage();
240       break;
241     }
242
243     case PerformanceProtocol::ENABLE_TIME_MARKER_BIT_MASK:
244     {
245       mMarkerBitmask = static_cast<PerformanceMarker::MarkerFilter>(param);
246       response       = "enable time marker ";
247       break;
248     }
249
250     case PerformanceProtocol::DUMP_SCENE_GRAPH:
251     {
252       TriggerOnMainThread(mClientId, mSendDataInterface, [&](AutomationCallback* callback){callback->AssignDumpSceneCommand();});
253       break;
254     }
255
256     case PerformanceProtocol::SET_PROPERTIES:
257     {
258       TriggerOnMainThread(mClientId, mSendDataInterface, [&](AutomationCallback* callback){callback->AssignSetPropertyCommand(stringParam);});
259       response = "Completed";
260       break;
261     }
262
263     case PerformanceProtocol::CUSTOM_COMMAND:
264     {
265       TriggerOnMainThread(mClientId, mSendDataInterface, [&](AutomationCallback* callback){callback->AssignCustomCommand(std::move(stringParam));});
266       response = "Completed";
267       break;
268     }
269
270     case PerformanceProtocol::LIST_METRICS_AVAILABLE:
271     case PerformanceProtocol::ENABLE_METRIC:
272     case PerformanceProtocol::DISABLE_METRIC:
273     {
274       response = "Metrics currently not supported";
275       break;
276     }
277     default:
278     {
279       response = UNKNOWN_CMD;
280       break;
281     }
282   }
283   if(!response.empty())
284   {
285     // add a carriage return for console clients
286     if(mConsoleClient)
287     {
288       response += "\n";
289     }
290     WriteSocket(response.c_str(), response.length());
291   }
292 }
293
294 } // namespace Adaptor
295
296 } // namespace Internal
297
298 } // namespace Dali