2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
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
9 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 * @file FIo_ChannelCAppStub.cpp
20 * @brief This is the implementation file for the _ChannelCAppStub class.
30 #include <unique_ptr.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
39 #include <sys/smack.h>
41 #include <FBase_StringConverter.h>
42 #include <FBaseDataType.h>
43 #include <FBaseLong.h>
44 #include <FBaseColArrayList.h>
46 #include <FBaseRt_EventDispatcher.h>
47 #include <FBaseSysLog.h>
48 #include <FBaseUtilStringTokenizer.h>
49 #include <FIo_ChannelServiceStub.h>
50 #include <FApp_AppInfo.h>
52 #include "FIo_ChannelCAppStub.h"
54 #define MAX_BUFFER_LENGTH 4096
56 static const int TOKEN_LENGTH = 7;
57 static const int CAPP_PADDING_LENGTH = 7;
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;
70 namespace Tizen { namespace Io
73 _ChannelCAppStub::_ChannelCAppStub(void)
74 :__pChannelService(null)
75 , __pGMainContext(null)
76 , __pConnectGSource(null)
80 _ChannelCAppStub::~_ChannelCAppStub(void)
82 if (__pConnectGSource != null)
84 g_source_destroy(__pConnectGSource);
85 g_source_unref(__pConnectGSource);
86 __pConnectGSource = null;
91 _ChannelCAppStub::_ChannelInfo::_ChannelInfo(void)
99 _ChannelCAppStub::_ChannelInfo::~_ChannelInfo(void)
101 if (pGIOChannel != null)
103 g_io_channel_unref(pGIOChannel);
106 if (pGSource != null)
110 g_source_destroy(pGSource);
113 g_source_unref(pGSource);
117 _ChannelCAppStub::_ClientInfo::_ClientInfo(void)
124 _ChannelCAppStub::_ClientInfo::~_ClientInfo(void)
130 _ChannelCAppStub::Construct(void)
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;
140 result r = E_SUCCESS;
142 socketNameLength = strlen(pSocketName) + 1;
143 SysTryReturnResult(NID_IO, socketNameLength < 108, E_SYSTEM,
144 "Server name is too long.");
146 __pGMainContext = g_main_context_get_thread_default(); //get own gmain context except default thread
147 if (__pGMainContext == null)
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.");
154 ret = unlink(pSocketName);
155 SysTryLog(NID_IO, ret == 0, "Unlinking a socket %s has failed.. but it is not a problem.", pSocketName);
157 serverSocket = socket(AF_UNIX, SOCK_STREAM, 0);
158 SysTryReturnResult(NID_IO, serverSocket != -1, E_SYSTEM,
159 "Failed to create a socket.");
161 // SMACK (Add a * label to socket)
162 if(smack_fsetlabel(serverSocket, "@", SMACK_LABEL_IPOUT) != 0)
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.");
168 if(smack_fsetlabel(serverSocket, "*", SMACK_LABEL_IPIN) != 0)
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.");
174 bzero(&serverAddress, sizeof(serverAddress));
175 serverAddress.sun_family = AF_UNIX;
176 strncpy(serverAddress.sun_path, pSocketName, socketNameLength);
177 serverLen = sizeof(serverAddress);
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));
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));
188 listen(serverSocket, 5);
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.");
194 // socket will be closed when pGIOChannel is deleted.
195 g_io_channel_set_close_on_unref(pGIOChannel, TRUE);
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.");
202 // channel will be delete when pGSource is deleted.
203 g_io_channel_unref(pGIOChannel);
206 g_source_set_callback(pGSource, (GSourceFunc) OnConnectionRequest, this, NULL);
207 g_source_attach(pGSource, __pGMainContext);
209 __pConnectGSource = pGSource;
214 if (pGIOChannel != null)
216 g_io_channel_unref(pGIOChannel);
219 if (serverSocket != -1)
226 g_main_context_unref(__pGMainContext);
227 __pGMainContext = null;
234 _ChannelCAppStub::SetChannelService(_ChannelService& service)
236 __pChannelService = &service;
246 _ChannelCAppStub::OnConnectionRequest(GIOChannel* source, GIOCondition condition, gpointer data)
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;
260 _ChannelCAppStub* pChannelStub = static_cast< _ChannelCAppStub* >(data);
261 SysTryReturn(NID_IO, pChannelStub != null, FALSE, E_SYSTEM,
262 "[E_SYSTEM] pChannelStub is null.");
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.");
269 readSize = read(clientFd, &helloMessage, sizeof(helloMessage));
270 helloMessage.appId[255] = '\0';
272 SysLog(NID_IO, " >> Channel Service: accepted client fd: %d, client: %d, app: %s",
273 clientFd, helloMessage.pid, helloMessage.appId);
275 pGIOChannel = g_io_channel_unix_new(clientFd);
276 SysTryCatch(NID_IO, pGIOChannel != null, , E_SYSTEM,
277 "[E_SYSTEM] Failed to create GIOChannel.");
279 g_io_channel_set_encoding(pGIOChannel, NULL, &pGError);
280 g_io_channel_set_flags(pGIOChannel, G_IO_FLAG_NONBLOCK, &pGError);
282 g_io_channel_set_close_on_unref(pGIOChannel, TRUE);
285 pClientInfo = pChannelStub->__clients[helloMessage.pid];
286 if (pClientInfo == null) // first connection request from this client
288 SysLog(NID_IO, "First connection!! [%s]", helloMessage.appId);
290 pClientInfo = new (std::nothrow) _ClientInfo;
291 SysTryCatch(NID_IO, pClientInfo != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
293 pClientInfo->pChannelStub = pChannelStub;
294 pClientInfo->clientId = helloMessage.pid;
295 pClientInfo->appId = helloMessage.appId;
297 pChannelStub->__clients[helloMessage.pid] = pClientInfo;
300 pChannelInfo = new (std::nothrow) _ChannelInfo;
301 SysTryCatch(NID_IO, pChannelInfo != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
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);
307 pChannelInfo->pClientInfo = pClientInfo;
308 pChannelInfo->pGIOChannel = pGIOChannel;
309 pChannelInfo->pGSource = pGSource;
311 pClientInfo->channels.push_back(pChannelInfo);
313 // Stores client info to _ChannelService
314 pChannelStub->__pChannelService->RegisterChannel(pClientInfo->appId, helloMessage.pid, pGIOChannel);
319 if (pGIOChannel != null)
321 g_io_channel_unref(pGIOChannel);
333 _ChannelCAppStub::OnReadMessage(GIOChannel* source, GIOCondition condition, gpointer data)
335 gboolean ret = FALSE;
337 _ChannelInfo* pChannelInfo = (_ChannelInfo*) data;
338 _ClientInfo* pClientInfo = pChannelInfo->pClientInfo;
339 _ChannelCAppStub* pChannelStub = (_ChannelCAppStub*) pClientInfo->pChannelStub;
341 ret = pChannelStub->HandleReceivedMessage(source, condition, data);
347 _ChannelCAppStub::HandleReceivedMessage(GIOChannel* source, GIOCondition condition, gpointer data)
350 GError* pGError = null;
352 result r = E_SUCCESS;
354 SysLog(NID_IO, "fd: %d, condition :0x%x", g_io_channel_unix_get_fd(source), condition);
356 _ChannelInfo* pChannelInfo = (_ChannelInfo*) data;
357 _ClientInfo* pClientInfo = pChannelInfo->pClientInfo;
358 _ChannelCAppStub* pChannelStub = pClientInfo->pChannelStub;
360 if (condition & G_IO_HUP)
362 SysLog(NID_IO, " G_IO_HUP, the connection is closed");
363 int clientId = pClientInfo->clientId;
365 g_io_channel_shutdown(source, FALSE, &pGError);
367 for (unsigned int i = 0; i < pClientInfo->channels.size(); i++)
369 if (pChannelInfo == pClientInfo->channels[i])
371 pClientInfo->channels.erase(pClientInfo->channels.begin() + i);
373 pChannelInfo->destroySource = false;
381 if (pClientInfo->channels.size() == 0)
383 SysLog(NID_IO, "All connections of client(%d) are closed. delete client info", clientId);
385 pChannelStub->__pChannelService->UnregisterChannel(clientId);
387 __clients[clientId] = null;
394 else if (condition & G_IO_IN)
396 unique_ptr<char[]> pBuffer(new char[MAX_BUFFER_LENGTH]);
398 status = g_io_channel_read_chars(source, pBuffer.get(), MAX_BUFFER_LENGTH, &readBytes, &pGError);
399 if (status != G_IO_STATUS_NORMAL)
401 if (status == G_IO_STATUS_EOF || status == G_IO_STATUS_ERROR)
403 if (status == G_IO_STATUS_EOF)
405 SysLog(NID_IO, "G_IO_STATUS_EOF, the connection is closed.");
409 SysLog(NID_IO, "G_IO_STATUS_ERROR, the connection is closed. ");
413 g_io_channel_shutdown(source, FALSE, &pGError);
415 int clientId = pClientInfo->clientId;
417 for (unsigned int i = 0; i < pClientInfo->channels.size(); i++)
419 if (pChannelInfo == pClientInfo->channels[i])
421 pClientInfo->channels.erase(pClientInfo->channels.begin() + i);
423 //pChannelInfo->destroySource = false;
424 pChannelInfo->destroySource = true;
430 if (pClientInfo->channels.size() == 0)
432 SysLog(NID_IO, "All connections of client(%d) are closed. delete client info", clientId);
434 pChannelStub->__pChannelService->UnregisterChannel(clientId);
436 __clients[clientId] = null;
445 SysSecureLog(NID_IO, "CAppChannel >> Channel Server: readBytes: %d, readBuf: %s", readBytes, pBuffer.get());
447 SysTryReturn(NID_IO, readBytes != 0, FALSE, E_SYSTEM, "[E_SYSTEM] Received data is empty.");
449 String srcAppId = pClientInfo->appId;
452 string buffer(pBuffer.get());
453 string tokenStr("::");
458 lastPos = buffer.find(tokenStr);
461 String appId((buffer.substr(pos, lastPos-pos)).c_str());
463 SysLog(NID_IO, "CAppChannel >> src = %ls / dest = %ls", srcAppId.GetPointer(), appId.GetPointer());
465 pos = lastPos + tokenStr.length();
466 lastPos = buffer.find(tokenStr, pos);
469 string requestId(buffer.substr(pos, lastPos-pos));
470 reqId = atol(requestId.c_str());
472 SysLog(NID_IO, "CAppChannel >> request = %d", reqId);
474 pos = lastPos + tokenStr.length();
480 size_t bufferSize = buffer.length();
483 while (pos < bufferSize)
485 // Get length of each token
486 token = buffer.substr(pos, TOKEN_LENGTH);
489 if (token == "0000000")
491 SysLog(NID_IO, "CAppChannel >> length = 0, token = empty string");
492 list.Add(*(new String()));
496 tokenCount = atoi(token.c_str());
497 token = buffer.substr(pos, tokenCount);
500 SysLog(NID_IO, "CAppChannel >> length = %d, token = %s", tokenCount, token.c_str());
501 list.Add(*(new String(token.c_str())));
505 r = pChannelStub->__pChannelService->SendRequest(srcAppId, appId, list, reqId);
506 SysTryReturn(NID_IO, !IsFailed(r), FALSE, E_SYSTEM, "[E_SYSTEM] Failed to send request.");
508 list.RemoveAll(true);
512 SysLog(NID_IO, " >> Channel Service: else !!!");
519 _ChannelCAppStub::SendResponse(int requestId, void* pGIOChannel, const ArrayList& args)
521 gsize writtenBytes = 0;
522 GError* pGError = null;
528 int count = args.GetCount();
530 int paddingLength = 0;
531 result r = E_SUCCESS;
532 SysLog(NID_IO, "item count: %d", count);
534 for (int i = 0; i < count; ++i)
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.");
544 paddingLength = CAPP_PADDING_LENGTH - lengthString.GetLength();
545 for (int j = 0; j < paddingLength; j++)
547 r = item.Insert(L'0', 0);
548 SysTryReturn(NID_IO, !IsFailed(r), false, E_SYSTEM, "[E_SYSTEM] Failed to compose the response message.");
554 SysSecureLog(NID_IO, "data: %ls, length: %d", str.GetPointer(), str.GetLength());
558 str.Append(requestId);
562 unique_ptr<char[]> pStr(_StringConverter::CopyToCharArrayN(str));
564 itemLength = strlen(pStr.get());
566 g_io_channel_write_chars((GIOChannel*)pGIOChannel, (char*)pStr.get(), itemLength, &writtenBytes, &pGError);
567 g_io_channel_flush((GIOChannel*)pGIOChannel, &pGError);