Apply secure logs
[platform/framework/native/channel-service.git] / src / FIo_ChannelCAppStub.cpp
1 //
2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17
18 /**
19  * @file        FIo_ChannelCAppStub.cpp
20  * @brief       This is the implementation file for the  _ChannelCAppStub class.
21  *
22  */
23
24 #include <cstdio>
25 #include <cstdlib>
26 #include <cstring>
27 #include <cerrno>
28 #include <iostream>
29
30 #include <unique_ptr.h>
31
32 #include <unistd.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/stat.h>
36 #include <sys/un.h>
37 #include <errno.h>
38
39 #include <FBase_StringConverter.h>
40 #include <FBaseDataType.h>
41 #include <FBaseLong.h>
42 #include <FBaseColArrayList.h>
43
44 #include <FBaseRt_EventDispatcher.h>
45 #include <FBaseSysLog.h>
46 #include <FBaseUtilStringTokenizer.h>
47 #include <FIo_ChannelServiceStub.h>
48 #include <FApp_AppInfo.h>
49
50 #include "FIo_ChannelCAppStub.h"
51
52 #define MAX_BUFFER_LENGTH 4096
53
54 static const int TOKEN_LENGTH = 7;
55 static const int CAPP_PADDING_LENGTH = 7;
56
57 using namespace std;
58
59 using namespace Tizen::Base;
60 using namespace Tizen::Base::Collection;
61 using namespace Tizen::Base::Runtime;
62 using namespace Tizen::Base::Utility;
63 using namespace Tizen::Io;
64 using namespace Tizen::App;
65
66 using namespace std;
67
68 namespace Tizen { namespace Io
69 {
70
71 _ChannelCAppStub::_ChannelCAppStub(void)
72         :__pChannelService(null)
73         , __pGMainContext(null)
74         , __pConnectGSource(null)
75 {
76 }
77
78 _ChannelCAppStub::~_ChannelCAppStub(void)
79 {
80         if (__pConnectGSource != null)
81         {
82                 g_source_destroy(__pConnectGSource);
83                 g_source_unref(__pConnectGSource);
84                 __pConnectGSource = null;
85         }
86         __clients.clear();
87 }
88
89 _ChannelCAppStub::_ChannelInfo::_ChannelInfo(void)
90         : pClientInfo(null)
91         , pGIOChannel(null)
92         , pGSource(null)
93         , destroySource(true)
94 {
95
96 }
97 _ChannelCAppStub::_ChannelInfo::~_ChannelInfo(void)
98 {
99         if (pGIOChannel != null)
100         {
101                 g_io_channel_unref(pGIOChannel);
102         }
103
104         if (pGSource != null)
105         {
106                 if (destroySource)
107                 {
108                         g_source_destroy(pGSource);
109                 }
110
111                 g_source_unref(pGSource);
112         }
113 }
114
115 _ChannelCAppStub::_ClientInfo::_ClientInfo(void)
116         : clientId(-1)
117         , pChannelStub(null)
118 {
119
120 }
121
122 _ChannelCAppStub::_ClientInfo::~_ClientInfo(void)
123 {
124         channels.clear();
125 }
126
127 result
128 _ChannelCAppStub::Construct(void)
129 {
130         GSource* pGSource = null;
131         GIOChannel* pGIOChannel = null;
132         const char* pSocketName = "/tmp/osp.io.socketserver.channelmanager\0";
133         size_t socketNameLength = 0;
134         struct sockaddr_un serverAddress;
135         int serverSocket = -1;
136         socklen_t serverLen = 0;
137         int ret = 0;
138         result r = E_SUCCESS;
139
140         socketNameLength = strlen(pSocketName) + 1;
141         SysTryReturnResult(NID_IO, socketNameLength < 108, E_SYSTEM,
142                         "Server name is too long.");
143
144         __pGMainContext = g_main_context_get_thread_default(); //get own gmain context except default thread
145         if (__pGMainContext == null)
146         {
147                 __pGMainContext = g_main_context_default(); //get gmain context from me (default)
148                 SysTryReturnResult(NID_IO, __pGMainContext != null, E_SYSTEM,
149                                 "Failed to get glib context.");
150         }
151
152         ret = unlink(pSocketName);
153         SysTryLog(NID_IO, ret == 0, "Unlinking a socket %s has failed.. but it is not a problem.", pSocketName);
154
155         serverSocket = socket(AF_UNIX, SOCK_STREAM, 0);
156         SysTryReturnResult(NID_IO, serverSocket != -1, E_SYSTEM,
157                         "Failed to create a socket.");
158
159         bzero(&serverAddress, sizeof(serverAddress));
160         serverAddress.sun_family = AF_UNIX;
161         strncpy(serverAddress.sun_path, pSocketName, socketNameLength);
162         serverLen = sizeof(serverAddress);
163
164         ret = bind(serverSocket, (const struct sockaddr*) &serverAddress, serverLen);
165         SysTryCatch(NID_IO, ret != -1, r = E_SYSTEM, E_SYSTEM,
166                         "[E_SYSTEM] Failed to bind a socket(%d, %s): %s", serverSocket, pSocketName, strerror(errno));
167
168         ret = chmod(pSocketName, 0666);
169         SysTryCatch(NID_IO, ret == 0, r = E_SYSTEM, E_SYSTEM,
170                         "[E_SYSTEM] Failed to change permission of a socket(%d, %s): %s", serverSocket,
171                         pSocketName, strerror(errno));
172
173         listen(serverSocket, 5);
174
175         pGIOChannel = g_io_channel_unix_new(serverSocket);
176         SysTryCatch(NID_IO, pGIOChannel != null, r = E_SYSTEM, E_SYSTEM,
177                         "[E_SYSTEM] Failed to create GIOChannel for socket.");
178
179         // socket will be closed when pGIOChannel is deleted.
180         g_io_channel_set_close_on_unref(pGIOChannel, TRUE);
181         serverSocket = -1;
182
183         pGSource = g_io_create_watch(pGIOChannel, (GIOCondition)(G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP));
184         SysTryCatch(NID_IO, pGSource != null, r = E_SYSTEM, E_SYSTEM,
185                         "[E_SYSTEM] Failed to create GSource for socket.");
186
187         // channel will be delete when pGSource is deleted.
188         g_io_channel_unref(pGIOChannel);
189         pGIOChannel = null;
190
191         g_source_set_callback(pGSource, (GSourceFunc) OnConnectionRequest, this, NULL);
192         g_source_attach(pGSource, __pGMainContext);
193
194         __pConnectGSource = pGSource;
195
196         return E_SUCCESS;
197
198 CATCH:
199         if (pGIOChannel != null)
200         {
201                 g_io_channel_unref(pGIOChannel);
202         }
203
204         if (serverSocket != -1)
205         {
206                 close(serverSocket);
207         }
208
209         if (__pGMainContext)
210         {
211                 g_main_context_unref(__pGMainContext);
212                 __pGMainContext = null;
213         }
214
215         return r;
216 }
217
218 void
219 _ChannelCAppStub::SetChannelService(_ChannelService& service)
220 {
221         __pChannelService = &service;
222 }
223
224 struct HelloMessage
225 {
226         int pid;
227         char appId[256];
228 };
229
230 gboolean
231 _ChannelCAppStub::OnConnectionRequest(GIOChannel* source, GIOCondition condition, gpointer data)
232 {
233         int serverFd = -1;
234         int clientFd = -1;
235         struct sockaddr_un clientAddress;
236         socklen_t clientLen = sizeof(clientAddress);
237         GSource* pGSource = null;
238         GIOChannel* pGIOChannel = null;
239         GError* pGError = null;
240         _ClientInfo* pClientInfo = null;
241         _ChannelInfo* pChannelInfo = null;
242         HelloMessage helloMessage;
243         int readSize = 0;
244
245         _ChannelCAppStub* pChannelStub = static_cast< _ChannelCAppStub* >(data);
246         SysTryReturn(NID_IO, pChannelStub != null, FALSE, E_SYSTEM,
247                         "[E_SYSTEM] pChannelStub is null.");
248
249         serverFd = g_io_channel_unix_get_fd(source);
250         clientFd = accept(serverFd, (struct sockaddr*) &clientAddress, &clientLen);
251         SysTryReturn(NID_IO, clientFd != -1, E_SYSTEM, FALSE, "[E_SYSTEM] Failed to accept.");
252
253
254         readSize = read(clientFd, &helloMessage, sizeof(helloMessage));
255         helloMessage.appId[255] = '\0';
256
257         SysLog(NID_IO, " >> Channel Service: accepted client fd: %d, client: %d, app: %s",
258                         clientFd, helloMessage.pid, helloMessage.appId);
259
260         pGIOChannel = g_io_channel_unix_new(clientFd);
261         SysTryCatch(NID_IO, pGIOChannel != null, , E_SYSTEM,
262                         "[E_SYSTEM] Failed to create GIOChannel.");
263
264         g_io_channel_set_encoding(pGIOChannel, NULL, &pGError);
265         g_io_channel_set_flags(pGIOChannel, G_IO_FLAG_NONBLOCK, &pGError);
266
267         g_io_channel_set_close_on_unref(pGIOChannel, TRUE);
268         clientFd = -1;
269
270         pClientInfo = pChannelStub->__clients[helloMessage.pid];
271         if (pClientInfo == null) // first connection request from this client
272         {
273                 SysLog(NID_IO, "First connection!! [%s]", helloMessage.appId);
274
275                 pClientInfo = new (std::nothrow) _ClientInfo;
276                 SysTryCatch(NID_IO, pClientInfo != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
277
278                 pClientInfo->pChannelStub = pChannelStub;
279                 pClientInfo->clientId = helloMessage.pid;
280                 pClientInfo->appId = helloMessage.appId;
281
282                 pChannelStub->__clients[helloMessage.pid] = pClientInfo;
283         }
284
285         pChannelInfo = new (std::nothrow) _ChannelInfo;
286         SysTryCatch(NID_IO, pChannelInfo != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
287
288         pGSource = g_io_create_watch(pGIOChannel, (GIOCondition) (G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP));
289         g_source_set_callback(pGSource, (GSourceFunc) OnReadMessage, pChannelInfo, NULL);
290         g_source_attach(pGSource, pChannelStub->__pGMainContext);
291
292         pChannelInfo->pClientInfo = pClientInfo;
293         pChannelInfo->pGIOChannel = pGIOChannel;
294         pChannelInfo->pGSource = pGSource;
295
296         pClientInfo->channels.push_back(pChannelInfo);
297
298         // Stores client info to _ChannelService
299         pChannelStub->__pChannelService->RegisterChannel(pClientInfo->appId, helloMessage.pid, pGIOChannel);
300
301         return TRUE;
302
303 CATCH:
304         if (pGIOChannel != null)
305         {
306                 g_io_channel_unref(pGIOChannel);
307         }
308
309         if (clientFd != -1)
310         {
311                 close(clientFd);
312         }
313
314         return FALSE;
315 }
316
317 gboolean
318 _ChannelCAppStub::OnReadMessage(GIOChannel* source, GIOCondition condition, gpointer data)
319 {
320         gboolean ret = FALSE;
321
322         _ChannelInfo* pChannelInfo = (_ChannelInfo*) data;
323         _ClientInfo* pClientInfo = pChannelInfo->pClientInfo;
324         _ChannelCAppStub* pChannelStub = (_ChannelCAppStub*) pClientInfo->pChannelStub;
325
326         ret = pChannelStub->HandleReceivedMessage(source, condition, data);
327
328         return ret;
329 }
330
331 gboolean
332 _ChannelCAppStub::HandleReceivedMessage(GIOChannel* source, GIOCondition condition, gpointer data)
333 {
334         GIOStatus status;
335         GError* pGError = null;
336         gsize readBytes = 0;
337         result r = E_SUCCESS;
338
339         SysLog(NID_IO, "fd: %d, condition :0x%x", g_io_channel_unix_get_fd(source), condition);
340
341         _ChannelInfo* pChannelInfo = (_ChannelInfo*) data;
342         _ClientInfo* pClientInfo = pChannelInfo->pClientInfo;
343         _ChannelCAppStub* pChannelStub = pClientInfo->pChannelStub;
344
345         if (condition & G_IO_HUP)
346         {
347                 SysLog(NID_IO, " G_IO_HUP, the connection is closed");
348                 int clientId = pClientInfo->clientId;
349
350                 g_io_channel_shutdown(source, FALSE, &pGError);
351
352                 for (unsigned int i = 0; i < pClientInfo->channels.size(); i++)
353                 {
354                         if (pChannelInfo == pClientInfo->channels[i])
355                         {
356                                 pClientInfo->channels.erase(pClientInfo->channels.begin() + i);
357
358                                 pChannelInfo->destroySource = false;
359                                 delete pChannelInfo;
360
361                                 break;
362                         }
363
364                 }
365
366                 if (pClientInfo->channels.size() == 0)
367                 {
368                         SysLog(NID_IO, "All connections of client(%d) are closed. delete client info", clientId);
369
370                         pChannelStub->__pChannelService->UnregisterChannel(clientId);
371
372                         __clients[clientId] = null;
373
374                         delete pClientInfo;
375                 }
376
377                 return FALSE;
378         }
379         else if (condition & G_IO_IN)
380         {
381                 unique_ptr<char[]> pBuffer(new char[MAX_BUFFER_LENGTH]);
382                 pGError = null;
383                 status = g_io_channel_read_chars(source, pBuffer.get(), MAX_BUFFER_LENGTH, &readBytes, &pGError);
384                 if (status != G_IO_STATUS_NORMAL)
385                 {
386                         if (status == G_IO_STATUS_EOF || status == G_IO_STATUS_ERROR)
387                         {
388                                 if (status == G_IO_STATUS_EOF)
389                                 {
390                                         SysLog(NID_IO, "G_IO_STATUS_EOF, the connection is closed.");
391                                 }
392                                 else
393                                 {
394                                         SysLog(NID_IO, "G_IO_STATUS_ERROR, the connection is closed. ");
395                                 }
396
397                                 pGError = null;
398                                 g_io_channel_shutdown(source, FALSE, &pGError);
399
400                                 int clientId = pClientInfo->clientId;
401
402                                 for (unsigned int i = 0; i < pClientInfo->channels.size(); i++)
403                                 {
404                                         if (pChannelInfo == pClientInfo->channels[i])
405                                         {
406                                                 pClientInfo->channels.erase(pClientInfo->channels.begin() + i);
407
408                                                 //pChannelInfo->destroySource = false;
409                                                 pChannelInfo->destroySource = true;
410                                                 delete pChannelInfo;
411                                                 break;
412                                         }
413                                 }
414
415                                 if (pClientInfo->channels.size() == 0)
416                                 {
417                                         SysLog(NID_IO, "All connections of client(%d) are closed. delete client info", clientId);
418
419                                         pChannelStub->__pChannelService->UnregisterChannel(clientId);
420
421                                         __clients[clientId] = null;
422
423                                         delete pClientInfo;
424                                 }
425
426                                 return FALSE;
427                         }
428                 }
429
430                 SysSecureLog(NID_IO, "CAppChannel >> Channel Server: readBytes: %d, readBuf: %s", readBytes, pBuffer.get());
431
432                 SysTryReturn(NID_IO, readBytes != 0, FALSE, E_SYSTEM, "[E_SYSTEM] Received data is empty.");
433
434                 String srcAppId = pClientInfo->appId;
435
436                 // Parse the header
437                 string buffer(pBuffer.get());
438                 string tokenStr("::");
439                 RequestId reqId = 0;
440                 size_t pos = 0;
441                 size_t lastPos = 0;
442
443                 lastPos = buffer.find(tokenStr);
444
445                 // AppId
446                 String appId((buffer.substr(pos, lastPos-pos)).c_str());
447
448                 SysLog(NID_IO, "CAppChannel >> src = %ls / dest = %ls", srcAppId.GetPointer(), appId.GetPointer());
449
450                 pos = lastPos + tokenStr.length();
451                 lastPos = buffer.find(tokenStr, pos);
452
453                 // Request ID
454                 string requestId(buffer.substr(pos, lastPos-pos));
455                 reqId = atol(requestId.c_str());
456
457                 SysLog(NID_IO, "CAppChannel >> request = %d", reqId);
458
459                 pos = lastPos + tokenStr.length();
460
461                 // Parse the data
462                 ArrayList list;
463                 list.Construct();
464
465                 size_t bufferSize = buffer.length();
466                 int tokenCount = 0;
467                 string token;
468                 while (pos < bufferSize)
469                 {
470                         // Get length of each token
471                         token = buffer.substr(pos, TOKEN_LENGTH);
472                         pos += TOKEN_LENGTH;
473
474                         if (token == "0000000")
475                         {
476                                 SysLog(NID_IO, "CAppChannel >> length = 0, token = empty string");
477                                 list.Add(*(new String()));
478                         }
479                         else
480                         {
481                                 tokenCount = atoi(token.c_str());
482                                 token = buffer.substr(pos, tokenCount);
483                                 pos += tokenCount;
484
485                                 SysLog(NID_IO, "CAppChannel >> length = %d, token = %s", tokenCount, token.c_str());
486                                 list.Add(*(new String(token.c_str())));
487                         }
488                 }
489
490                 r = pChannelStub->__pChannelService->SendRequest(srcAppId, appId, list, reqId);
491                 SysTryReturn(NID_IO, !IsFailed(r), FALSE, E_SYSTEM, "[E_SYSTEM] Failed to send request.");
492
493                 list.RemoveAll(true);
494         }
495         else
496         {
497                 SysLog(NID_IO, " >> Channel Service: else !!!");
498         }
499
500         return TRUE;
501 }
502
503 bool
504 _ChannelCAppStub::SendResponse(int requestId, void* pGIOChannel, const ArrayList& args)
505 {
506         gsize writtenBytes = 0;
507         GError* pGError = null;
508
509         // Parse the data
510         String str;
511         String item;
512         String lengthString;
513         int count = args.GetCount();
514         int itemLength = 0;
515         int paddingLength = 0;
516         result r = E_SUCCESS;
517         SysLog(NID_IO, "item count: %d", count);
518
519         for (int i = 0; i < count; ++i)
520         {
521                 item = *((String*)args.GetAt(i));
522                 unique_ptr<char[]> pItemStr(_StringConverter::CopyToCharArrayN(item));
523                 itemLength = strlen(pItemStr.get());
524                 lengthString = Integer::ToString(itemLength);
525                 r = item.Insert(lengthString, 0);
526                 SysTryReturn(NID_IO, !IsFailed(r), false, E_SYSTEM, "[E_SYSTEM] Failed to compose the response message.");
527
528                 // padding 7 digit
529                 paddingLength = CAPP_PADDING_LENGTH - lengthString.GetLength();
530                 for (int j = 0; j < paddingLength; j++)
531                 {
532                         r = item.Insert(L'0', 0);
533                         SysTryReturn(NID_IO, !IsFailed(r), false, E_SYSTEM, "[E_SYSTEM] Failed to compose the response message.");
534                 }
535
536                 str.Append(item);
537         }
538
539         SysSecureLog(NID_IO, "data: %ls, length: %d", str.GetPointer(), str.GetLength());
540
541         // Add a RequestId
542         str.Append(L"|||");
543         str.Append(requestId);
544         str.Append(L"|");
545
546         // Send a data
547         unique_ptr<char[]> pStr(_StringConverter::CopyToCharArrayN(str));
548
549         itemLength = strlen(pStr.get());
550
551         g_io_channel_write_chars((GIOChannel*)pGIOChannel, (char*)pStr.get(), itemLength, &writtenBytes, &pGError);
552         g_io_channel_flush((GIOChannel*)pGIOChannel, &pGError);
553
554         return true;
555 }
556
557 }}
558