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