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 <FBase_StringConverter.h>
40 #include <FBaseDataType.h>
41 #include <FBaseLong.h>
42 #include <FBaseColArrayList.h>
44 #include <FBaseRt_EventDispatcher.h>
45 #include <FBaseSysLog.h>
46 #include <FBaseUtilStringTokenizer.h>
47 #include <FIo_ChannelServiceStub.h>
48 #include <FApp_AppInfo.h>
50 #include "FIo_ChannelCAppStub.h"
52 #define MAX_BUFFER_LENGTH 4096
54 static const int TOKEN_LENGTH = 7;
55 static const int CAPP_PADDING_LENGTH = 7;
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;
68 namespace Tizen { namespace Io
71 _ChannelCAppStub::_ChannelCAppStub(void)
72 :__pChannelService(null)
73 , __pGMainContext(null)
74 , __pConnectGSource(null)
78 _ChannelCAppStub::~_ChannelCAppStub(void)
80 if (__pConnectGSource != null)
82 g_source_destroy(__pConnectGSource);
83 g_source_unref(__pConnectGSource);
84 __pConnectGSource = null;
89 _ChannelCAppStub::_ChannelInfo::_ChannelInfo(void)
97 _ChannelCAppStub::_ChannelInfo::~_ChannelInfo(void)
99 if (pGIOChannel != null)
101 g_io_channel_unref(pGIOChannel);
104 if (pGSource != null)
108 g_source_destroy(pGSource);
111 g_source_unref(pGSource);
115 _ChannelCAppStub::_ClientInfo::_ClientInfo(void)
122 _ChannelCAppStub::_ClientInfo::~_ClientInfo(void)
128 _ChannelCAppStub::Construct(void)
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;
138 result r = E_SUCCESS;
140 socketNameLength = strlen(pSocketName) + 1;
141 SysTryReturnResult(NID_IO, socketNameLength < 108, E_SYSTEM,
142 "Server name is too long.");
144 __pGMainContext = g_main_context_get_thread_default(); //get own gmain context except default thread
145 if (__pGMainContext == null)
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.");
152 ret = unlink(pSocketName);
153 SysTryLog(NID_IO, ret == 0, "Unlinking a socket %s has failed.. but it is not a problem.", pSocketName);
155 serverSocket = socket(AF_UNIX, SOCK_STREAM, 0);
156 SysTryReturnResult(NID_IO, serverSocket != -1, E_SYSTEM,
157 "Failed to create a socket.");
159 bzero(&serverAddress, sizeof(serverAddress));
160 serverAddress.sun_family = AF_UNIX;
161 strncpy(serverAddress.sun_path, pSocketName, socketNameLength);
162 serverLen = sizeof(serverAddress);
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));
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));
173 listen(serverSocket, 5);
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.");
179 // socket will be closed when pGIOChannel is deleted.
180 g_io_channel_set_close_on_unref(pGIOChannel, TRUE);
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.");
187 // channel will be delete when pGSource is deleted.
188 g_io_channel_unref(pGIOChannel);
191 g_source_set_callback(pGSource, (GSourceFunc) OnConnectionRequest, this, NULL);
192 g_source_attach(pGSource, __pGMainContext);
194 __pConnectGSource = pGSource;
199 if (pGIOChannel != null)
201 g_io_channel_unref(pGIOChannel);
204 if (serverSocket != -1)
211 g_main_context_unref(__pGMainContext);
212 __pGMainContext = null;
219 _ChannelCAppStub::SetChannelService(_ChannelService& service)
221 __pChannelService = &service;
231 _ChannelCAppStub::OnConnectionRequest(GIOChannel* source, GIOCondition condition, gpointer data)
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;
245 _ChannelCAppStub* pChannelStub = static_cast< _ChannelCAppStub* >(data);
246 SysTryReturn(NID_IO, pChannelStub != null, FALSE, E_SYSTEM,
247 "[E_SYSTEM] pChannelStub is null.");
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.");
254 readSize = read(clientFd, &helloMessage, sizeof(helloMessage));
255 helloMessage.appId[255] = '\0';
257 SysLog(NID_IO, " >> Channel Service: accepted client fd: %d, client pid: %d, appid: %s",
258 clientFd, helloMessage.pid, helloMessage.appId);
260 pGIOChannel = g_io_channel_unix_new(clientFd);
261 SysTryCatch(NID_IO, pGIOChannel != null, , E_SYSTEM,
262 "[E_SYSTEM] Failed to create GIOChannel.");
264 g_io_channel_set_encoding(pGIOChannel, NULL, &pGError);
265 g_io_channel_set_flags(pGIOChannel, G_IO_FLAG_NONBLOCK, &pGError);
267 g_io_channel_set_close_on_unref(pGIOChannel, TRUE);
270 pClientInfo = pChannelStub->__clients[helloMessage.pid];
271 if (pClientInfo == null) // first connection request from this client
273 SysLog(NID_IO, "First connection!! [%s]", helloMessage.appId);
275 pClientInfo = new (std::nothrow) _ClientInfo;
276 SysTryCatch(NID_IO, pClientInfo != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
278 pClientInfo->pChannelStub = pChannelStub;
279 pClientInfo->clientId = helloMessage.pid;
280 pClientInfo->appId = helloMessage.appId;
282 pChannelStub->__clients[helloMessage.pid] = pClientInfo;
285 pChannelInfo = new (std::nothrow) _ChannelInfo;
286 SysTryCatch(NID_IO, pChannelInfo != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
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);
292 pChannelInfo->pClientInfo = pClientInfo;
293 pChannelInfo->pGIOChannel = pGIOChannel;
294 pChannelInfo->pGSource = pGSource;
296 pClientInfo->channels.push_back(pChannelInfo);
298 // Stores client info to _ChannelService
299 pChannelStub->__pChannelService->RegisterChannel(pClientInfo->appId, helloMessage.pid, pGIOChannel);
304 if (pGIOChannel != null)
306 g_io_channel_unref(pGIOChannel);
318 _ChannelCAppStub::OnReadMessage(GIOChannel* source, GIOCondition condition, gpointer data)
320 gboolean ret = FALSE;
322 _ChannelInfo* pChannelInfo = (_ChannelInfo*) data;
323 _ClientInfo* pClientInfo = pChannelInfo->pClientInfo;
324 _ChannelCAppStub* pChannelStub = (_ChannelCAppStub*) pClientInfo->pChannelStub;
326 ret = pChannelStub->HandleReceivedMessage(source, condition, data);
332 _ChannelCAppStub::HandleReceivedMessage(GIOChannel* source, GIOCondition condition, gpointer data)
335 GError* pGError = null;
337 result r = E_SUCCESS;
339 SysLog(NID_IO, "fd: %d, condition :0x%x", g_io_channel_unix_get_fd(source), condition);
341 _ChannelInfo* pChannelInfo = (_ChannelInfo*) data;
342 _ClientInfo* pClientInfo = pChannelInfo->pClientInfo;
343 _ChannelCAppStub* pChannelStub = pClientInfo->pChannelStub;
345 if (condition & G_IO_HUP)
347 SysLog(NID_IO, " G_IO_HUP, the connection is closed");
348 int clientId = pClientInfo->clientId;
350 g_io_channel_shutdown(source, FALSE, &pGError);
352 for (unsigned int i = 0; i < pClientInfo->channels.size(); i++)
354 if (pChannelInfo == pClientInfo->channels[i])
356 pClientInfo->channels.erase(pClientInfo->channels.begin() + i);
358 pChannelInfo->destroySource = false;
366 if (pClientInfo->channels.size() == 0)
368 SysLog(NID_IO, "All connections of client(%d) are closed. delete client info", clientId);
370 pChannelStub->__pChannelService->UnregisterChannel(clientId);
372 __clients[clientId] = null;
379 else if (condition & G_IO_IN)
381 unique_ptr<char[]> pBuffer(new char[MAX_BUFFER_LENGTH]);
383 status = g_io_channel_read_chars(source, pBuffer.get(), MAX_BUFFER_LENGTH, &readBytes, &pGError);
384 if (status != G_IO_STATUS_NORMAL)
386 if (status == G_IO_STATUS_EOF || status == G_IO_STATUS_ERROR)
388 if (status == G_IO_STATUS_EOF)
390 SysLog(NID_IO, "G_IO_STATUS_EOF, the connection is closed.");
394 SysLog(NID_IO, "G_IO_STATUS_ERROR, the connection is closed. ");
398 g_io_channel_shutdown(source, FALSE, &pGError);
400 int clientId = pClientInfo->clientId;
402 for (unsigned int i = 0; i < pClientInfo->channels.size(); i++)
404 if (pChannelInfo == pClientInfo->channels[i])
406 pClientInfo->channels.erase(pClientInfo->channels.begin() + i);
408 //pChannelInfo->destroySource = false;
409 pChannelInfo->destroySource = true;
415 if (pClientInfo->channels.size() == 0)
417 SysLog(NID_IO, "All connections of client(%d) are closed. delete client info", clientId);
419 pChannelStub->__pChannelService->UnregisterChannel(clientId);
421 __clients[clientId] = null;
430 SysLog(NID_IO, "CAppChannel >> Channel Server: readBytes: %d, readBuf: %s", readBytes, pBuffer.get());
432 SysTryReturn(NID_IO, readBytes != 0, FALSE, E_SYSTEM, "[E_SYSTEM] Received data is empty.");
434 String srcAppId = pClientInfo->appId;
437 string buffer(pBuffer.get());
438 string tokenStr("::");
443 lastPos = buffer.find(tokenStr);
446 String appId((buffer.substr(pos, lastPos-pos)).c_str());
448 SysLog(NID_IO, "CAppChannel >> src = %ls / dest = %ls", srcAppId.GetPointer(), appId.GetPointer());
450 pos = lastPos + tokenStr.length();
451 lastPos = buffer.find(tokenStr, pos);
454 string requestId(buffer.substr(pos, lastPos-pos));
455 reqId = atol(requestId.c_str());
457 SysLog(NID_IO, "CAppChannel >> requestId = %d", reqId);
459 pos = lastPos + tokenStr.length();
465 size_t bufferSize = buffer.length();
468 while (pos < bufferSize)
470 // Get length of each token
471 token = buffer.substr(pos, TOKEN_LENGTH);
474 if (token == "0000000")
476 SysLog(NID_IO, "CAppChannel >> length = 0, token = empty string");
477 list.Add(*(new String()));
481 tokenCount = atoi(token.c_str());
482 token = buffer.substr(pos, tokenCount);
485 SysLog(NID_IO, "CAppChannel >> length = %d, token = %s", tokenCount, token.c_str());
486 list.Add(*(new String(token.c_str())));
490 r = pChannelStub->__pChannelService->SendRequest(srcAppId, appId, list, reqId);
491 SysTryReturn(NID_IO, !IsFailed(r), FALSE, E_SYSTEM, "[E_SYSTEM] Failed to send request.");
493 list.RemoveAll(true);
497 SysLog(NID_IO, " >> Channel Service: else !!!");
504 _ChannelCAppStub::SendResponse(int requestId, void* pGIOChannel, const ArrayList& args)
506 gsize writtenBytes = 0;
507 GError* pGError = null;
513 int count = args.GetCount();
515 int paddingLength = 0;
516 result r = E_SUCCESS;
517 SysLog(NID_IO, "item count: %d", count);
519 for (int i = 0; i < count; ++i)
521 item = *((String*)args.GetAt(i));
522 itemLength = item.GetLength();
523 lengthString = Integer::ToString(itemLength);
524 r = item.Insert(lengthString, 0);
525 SysTryReturn(NID_IO, !IsFailed(r), false, E_SYSTEM, "[E_SYSTEM] Failed to compose the response message.");
528 paddingLength = CAPP_PADDING_LENGTH - lengthString.GetLength();
529 for (int j = 0; j < paddingLength; j++)
531 r = item.Insert(L'0', 0);
532 SysTryReturn(NID_IO, !IsFailed(r), false, E_SYSTEM, "[E_SYSTEM] Failed to compose the response message.");
538 SysLog(NID_IO, "data: %ls, length: %d", str.GetPointer(), str.GetLength());
542 str.Append(requestId);
546 unique_ptr<char[]> pStr(_StringConverter::CopyToCharArrayN(str));
548 itemLength = strlen(pStr.get());
550 g_io_channel_write_chars((GIOChannel*)pGIOChannel, (char*)pStr.get(), itemLength, &writtenBytes, &pGError);
551 g_io_channel_flush((GIOChannel*)pGIOChannel, &pGError);