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_IpcServer.cpp
20 * @brief This is the implementation file for the _IpcServer class.
32 #include <sys/types.h>
33 #include <sys/socket.h>
37 #include <ipc/ipc_message.h>
39 #include <app_manager.h>
41 #include <FBaseRtMutex.h>
42 #include <FBaseSysLog.h>
43 #include <FBase_StringConverter.h>
44 #include <FBaseRt_EventDispatcher.h>
46 #include "FIo_IIpcServerEventListener.h"
47 #include "FIo_IpcServer.h"
51 using namespace Tizen::Base;
52 using namespace Tizen::Base::Runtime;
53 using namespace Tizen::App;
55 namespace Tizen { namespace Io
58 _IpcServer::_ChannelInfo::_ChannelInfo(void)
67 _IpcServer::_ChannelInfo::~_ChannelInfo(void)
69 if (pGIOChannel != null)
71 g_io_channel_unref(pGIOChannel);
78 g_source_destroy(pGSource);
81 g_source_unref(pGSource);
85 _IpcServer::_ClientInfo::_ClientInfo(void)
88 , pReverseChannel(null)
93 _IpcServer::_ClientInfo::~_ClientInfo(void)
95 if (pReverseChannel != null)
97 g_io_channel_unref(pReverseChannel);
103 _IpcServer::_IpcServer(void)
104 : __runOnCallerThread(false)
105 , __pEventDispatcher(null)
108 , __pHandlerGMainContext(null)
109 , __pHandlerGMainLoop(null)
110 , __pConnectGSource(null)
111 , __pCurrentChannel(null)
112 , __pCurrentClientInfo(null)
114 __messageBuffer[0] = '\0';
118 _IpcServer::~_IpcServer(void)
120 if (__pConnectGSource != null)
122 g_source_destroy(__pConnectGSource);
123 g_source_unref(__pConnectGSource);
124 __pConnectGSource = null;
127 if (!__runOnCallerThread)
129 if (__pEventDispatcher)
131 delete __pEventDispatcher;
132 __pEventDispatcher = null;
135 if (__pHandlerGMainLoop)
137 g_main_loop_unref(__pHandlerGMainLoop);
138 __pHandlerGMainLoop = null;
141 if (__pHandlerGMainContext)
143 g_main_context_unref(__pHandlerGMainContext);
144 __pHandlerGMainContext = null;
153 _IpcServer::Construct(const String& name, const _IIpcServerEventListener& listener, bool runOnCallerThread)
155 result r = E_SUCCESS;
157 GIOChannel* pGIOChannel = null;
158 GSource* pGSource = null;
160 struct sockaddr_un serverAddress;
161 int serverSocket = -1;
164 std::string socketName;
166 size_t socketNameLength = 0;
169 __pListener = const_cast <_IIpcServerEventListener*>(&listener);
170 __runOnCallerThread = runOnCallerThread;
172 pName = _StringConverter::CopyToCharArrayN(name);
173 SysTryReturnResult(NID_IO, pName != null, E_OUT_OF_MEMORY, "Not enough memory");
175 socketName.append("/tmp/");
176 socketName.append(pName);
180 socketNameLength = socketName.size() + 1;
181 SysTryReturnResult(NID_IO, socketNameLength < 108, E_INVALID_ARG, "Server name is too long");
183 if (!__runOnCallerThread)
185 __pHandlerGMainContext = g_main_context_new();
186 __pHandlerGMainLoop = g_main_loop_new(__pHandlerGMainContext, FALSE);
191 __pHandlerGMainContext = g_main_context_get_thread_default();
192 if (__pHandlerGMainContext == null) // is global?
194 __pHandlerGMainContext = g_main_context_default();
195 if (__pHandlerGMainContext == null)
202 ret = unlink(socketName.c_str());
203 SysTryLog(NID_IO, ret == 0, "Unlink a socket has failed.. but it is not a problem.");
205 serverSocket = socket(AF_UNIX, SOCK_STREAM, 0);
206 SysTryReturnResult(NID_IO, serverSocket != -1, E_SYSTEM, "Failed to create a socket.");
208 bzero(&serverAddress, sizeof(serverAddress));
209 serverAddress.sun_family = AF_UNIX;
210 strncpy(serverAddress.sun_path, socketName.c_str(), socketNameLength);
211 serverLen = sizeof(serverAddress);
213 ret = bind(serverSocket, (const struct sockaddr*) &serverAddress, serverLen);
214 SysTryCatch(NID_IO, ret != -1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to bind a socket(%d, %s): %s", serverSocket,
215 socketName.c_str(), strerror(errno));
217 ret = chmod(socketName.c_str(), 0666);
218 SysTryCatch(NID_IO, ret == 0, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to change permission of a socket(%d, %s): %s", serverSocket,
219 socketName.c_str(), strerror(errno));
221 ret = listen(serverSocket, 15);
222 SysTryCatch(NID_IO, ret == 0, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to listen the socket(%d, %s): %s", serverSocket,
223 socketName.c_str(), strerror(errno));
225 pGIOChannel = g_io_channel_unix_new(serverSocket);
226 SysTryCatch(NID_IO, pGIOChannel != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Not enough memory.");
228 // socket will be closed when pGIOChannel is deleted.
229 g_io_channel_set_close_on_unref(pGIOChannel, TRUE);
232 pGSource = g_io_create_watch(pGIOChannel, (GIOCondition) (G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP));
233 SysTryCatch(NID_IO, pGSource != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
234 "[E_OUT_OF_MEMORY] Failed to create watch for socket.");
236 // channel will be delete when pGSource is deleted.
237 g_io_channel_unref(pGIOChannel);
240 g_source_set_callback(pGSource, (GSourceFunc) OnConnectionRequest, this, NULL);
241 g_source_attach(pGSource, __pHandlerGMainContext);
243 if (__runOnCallerThread)
245 __pListener->OnIpcServerStarted(*this);
249 ret = pthread_create(&__handlerThread, null, &ThreadProc, (void*) this);
250 SysTryCatch(NID_IO, ret == 0, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to an IPC thread");
253 __pConnectGSource = pGSource;
260 if (pGIOChannel != null)
262 g_io_channel_unref(pGIOChannel);
265 if (serverSocket != -1)
270 if (runOnCallerThread && __pHandlerGMainContext)
272 g_main_context_unref(__pHandlerGMainContext);
273 __pHandlerGMainContext = null;
282 int reverse; // if the connection is for reverse message
286 _IpcServer::OnConnectionRequest(GIOChannel* source, GIOCondition condition, gpointer data)
288 _IpcServer* pIpcServer = (_IpcServer*) data;
289 GError* pGError = null;
290 HelloMessage helloMessage;
291 _ClientInfo* pClientInfo = null;
292 _ChannelInfo* pChannelInfo = null;
293 GSource* pGSource = null;
294 GIOChannel* pChannel = null;
298 struct sockaddr_un clientAddress;
299 socklen_t clientLen = sizeof(clientAddress);
301 SysAssertf(pIpcServer != null, "Not yet constructed. Construct() should be called before use.\n");
302 SysAssertf(pIpcServer->__pListener != null, "Listener is null.\n");
304 server = g_io_channel_unix_get_fd(source);
306 client = accept(server, (struct sockaddr*) &clientAddress, &clientLen);
307 SysTryCatch(NID_IO, client != -1, ,E_SYSTEM, "[E_SYSTEM] Accept failed.");
309 read(client, &helloMessage, sizeof(helloMessage));
311 pChannel = g_io_channel_unix_new(client);
312 SysTryCatch(NID_IO, pChannel != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Not enough memory.");
314 g_io_channel_set_encoding(pChannel, NULL, &pGError);
315 g_io_channel_set_flags(pChannel, G_IO_FLAG_NONBLOCK, &pGError);
317 g_io_channel_set_close_on_unref(pChannel, TRUE);
320 pClientInfo = pIpcServer->__clients[helloMessage.pid];
321 if (pClientInfo == null) // first connection request from this client
323 pClientInfo = new (std::nothrow) _ClientInfo;
324 SysTryCatch(NID_IO, pClientInfo != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Not enough memory.");
326 pClientInfo->pIpcServer = pIpcServer;
327 pClientInfo->clientId = helloMessage.pid;
330 int ret = app_manager_get_app_id(helloMessage.pid, &pAppId);
331 SysTryCatch(NID_IO, ret >= 0, delete pClientInfo, E_SYSTEM, "[E_SYSTEM] Failed to get_app_id: %d", ret);
333 pClientInfo->appId = pAppId;
336 pClientInfo->pReverseChannel = null;
338 pIpcServer->__clients[helloMessage.pid] = pClientInfo;
339 pIpcServer->__pCurrentClientInfo = pClientInfo;
340 pIpcServer->__pListener->OnIpcClientConnected(*pIpcServer, helloMessage.pid);
341 pIpcServer->__pCurrentClientInfo = null;
344 if (helloMessage.reverse != 0)
346 pClientInfo->pReverseChannel = pChannel;
350 pChannelInfo = new (std::nothrow) _ChannelInfo;
351 SysTryCatch(NID_IO, pChannelInfo != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Not enough memory.");
353 pGSource = g_io_create_watch(pChannel, (GIOCondition) (G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP));
354 g_source_set_callback(pGSource, (GSourceFunc) OnReadMessage, pChannelInfo, NULL);
355 g_source_attach(pGSource, pIpcServer->__pHandlerGMainContext);
357 pChannelInfo->pClientInfo = pClientInfo;
358 pChannelInfo->pGIOChannel = pChannel;
359 pChannelInfo->pGSource = pGSource;
361 pClientInfo->channels.push_back(pChannelInfo);
367 if (pChannel != null)
369 g_io_channel_unref(pChannel);
381 _IpcServer::GetClientId(void) const
383 if (__pCurrentClientInfo)
385 return __pCurrentClientInfo->clientId;
392 _IpcServer::GetClientProcessId(void) const
394 if (__pCurrentClientInfo)
396 return __pCurrentClientInfo->clientId;
403 _IpcServer::GetClientAppId(void) const
405 static String nullString;
407 if (__pCurrentClientInfo)
410 __pCurrentClientInfo->appId.SubString(0, 10, pkgId);
419 _IpcServer::GetClientAppExecutableName(void) const
421 static String nullString;
423 if (__pCurrentClientInfo)
426 __pCurrentClientInfo->appId.SubString(11, appName);
435 _IpcServer::GetClientPackageId(void) const
437 static String nullString;
439 if (__pCurrentClientInfo)
442 __pCurrentClientInfo->appId.SubString(0, 10, pkgId);
451 _IpcServer::GetClientApplicationId(void) const
453 static String nullString;
455 if (__pCurrentClientInfo)
457 return __pCurrentClientInfo->appId;
464 _IpcServer::HandleReceivedMessage(GIOChannel* source, GIOCondition condition, gpointer data)
466 GError* pGError = NULL;
468 IPC::Message* pMessage = NULL;
469 _ChannelInfo* pChannelInfo = (_ChannelInfo*) data;
470 _ClientInfo* pClientInfo = pChannelInfo->pClientInfo;
472 if (condition & G_IO_HUP)
474 SysLog(NID_IO, "G_IO_HUP, the connection is closed.");
476 int clientId = pClientInfo->clientId;
478 g_io_channel_shutdown(source, FALSE, &pGError);
480 for (unsigned int i = 0; i < pClientInfo->channels.size(); i++)
482 if (pChannelInfo == pClientInfo->channels[i])
484 pClientInfo->channels.erase(pClientInfo->channels.begin() + i);
486 // Do not destroy a source in a dispatch callback
487 // because main loop will do it if the callback return FALSE.
488 pChannelInfo->destroySource = false;
495 if (pClientInfo->channels.size() == 0)
497 SysLog(NID_IO, "All connections of client(%d) are closed. delete client info", clientId);
499 __pListener->OnIpcClientDisconnected(*this, clientId);
501 __clients[clientId] = null;
508 else if (condition & G_IO_IN)
511 const char* pStart = NULL;
512 const char* pEnd = NULL;
513 const char* pEndOfMessage = NULL;
518 status = g_io_channel_read_chars(source, (char*) __messageBuffer, __MAX_MESSAGE_BUFFER_SIZE, &readSize, &pGError);
519 if (status != G_IO_STATUS_NORMAL)
521 if (status == G_IO_STATUS_EOF || status == G_IO_STATUS_ERROR)
523 if (status == G_IO_STATUS_EOF)
525 SysLog(NID_IO, "G_IO_STATUS_EOF, the connection is closed.");
529 SysLog(NID_IO, "G_IO_STATUS_ERROR, the connection is closed. ");
533 g_io_channel_shutdown(source, FALSE, &pGError);
535 int clientId = pClientInfo->clientId;
537 for (unsigned int i = 0; i < pClientInfo->channels.size(); i++)
539 if (pChannelInfo == pClientInfo->channels[i])
541 pClientInfo->channels.erase(pClientInfo->channels.begin() + i);
543 pChannelInfo->destroySource = false;
549 if (pClientInfo->channels.size() == 0)
551 SysLog(NID_IO, "All connections of client(%d) are closed normally by the client.", clientId);
555 __pListener->OnIpcClientDisconnected(*this, clientId);
558 __clients[clientId] = null;
572 if (__pending.empty())
574 pStart = __messageBuffer;
575 pEnd = pStart + readSize;
579 __pending.append(__messageBuffer, readSize);
580 pStart = __pending.data();
581 pEnd = pStart + __pending.size();
586 pEndOfMessage = IPC::Message::FindNext(pStart, pEnd);
587 if (pEndOfMessage == NULL)
589 __pending.assign(pStart, pEnd - pStart);
593 pMessage = new (std::nothrow) IPC::Message(pStart, pEndOfMessage - pStart);
594 SysTryReturn(NID_IO, pMessage != null, FALSE, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
596 __pCurrentChannel = source;
600 __pListener->OnIpcRequestReceived(*this, *pMessage);
605 __pCurrentChannel = NULL;
607 pStart = pEndOfMessage;
620 _IpcServer::OnReadMessage(GIOChannel* source, GIOCondition condition, gpointer data)
622 gboolean ret = FALSE;
623 _ChannelInfo* pChannelInfo = (_ChannelInfo*) data;
624 _ClientInfo* pClientInfo = pChannelInfo->pClientInfo;
625 _IpcServer* pIpcServer = (_IpcServer*) pClientInfo->pIpcServer;
627 pIpcServer->__pCurrentClientInfo = pClientInfo;
628 ret = pIpcServer->HandleReceivedMessage(source, condition, data);
629 pIpcServer->__pCurrentClientInfo = null;
635 _IpcServer::ThreadProc(void* pParam)
637 _IpcServer* pIpcServer = (_IpcServer*) pParam;
638 if (pIpcServer != NULL)
640 pIpcServer->Run(NULL);
647 _IpcServer::Run(void* pParam)
649 result r = E_SUCCESS;
651 if (__pListener == null)
656 __pEventDispatcher = new (std::nothrow) _EventDispatcher;
657 SysTryReturnVoidResult(NID_IO, __pEventDispatcher != null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
659 r = __pEventDispatcher->Construct(__pHandlerGMainContext);
662 delete __pEventDispatcher;
663 __pEventDispatcher = null;
666 __pListener->OnIpcServerStarted(*this);
668 g_main_loop_run(__pHandlerGMainLoop);
670 __pListener->OnIpcServerStopped(*this);
674 _IpcServer::Start(void)
680 _IpcServer::GetName(void) const
686 _IpcServer::Stop(void)
688 result r = E_SUCCESS;
691 SysTryReturnResult(NID_IO, __pListener != null, E_SYSTEM, "Listener is null.");
693 if (!__runOnCallerThread)
695 pthread_t self = pthread_self();
697 if (__pHandlerGMainLoop)
699 g_main_loop_quit(__pHandlerGMainLoop);
702 if (__handlerThread != self)
704 ret = pthread_join(__handlerThread, null);
705 SysTryLog(NID_IO, ret == 0, "Join an IPC thread returns an error");
710 __pListener->OnIpcServerStopped(*this);
717 _IpcServer::Send(IPC::Message* msg)
722 GError* pGError = NULL;
725 pData = (char*) msg->data();
726 remain = msg->size();
733 g_io_channel_write_chars(__pCurrentChannel, (char*) pData, remain, &written, &pGError);
739 g_io_channel_flush(__pCurrentChannel, &pGError);
750 _IpcServer::SendResponse(int client, IPC::Message* pMessage)
752 result r = E_SUCCESS;
756 GError* pGError = null;
757 _ClientInfo* pClientInfo = null;
759 SysTryReturn(NID_IO, client >= 0 && pMessage != null, false, E_INVALID_ARG,
760 "[E_INVALID_ARG] pMessage(0x%x) is null or clinet(%d) < 0", pMessage,
762 SysTryCatch(NID_IO, !pMessage->is_sync(), r = E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] Can't send sync. messagee.");
764 pClientInfo = __clients[client];
765 SysTryCatch(NID_IO, pClientInfo != null, r = E_INVALID_ARG, E_INVALID_ARG,
766 "[E_INVALID_ARG] client(%d) has not been registered.",
769 pData = (char*) pMessage->data();
770 remain = pMessage->size();
775 g_io_channel_write_chars(pClientInfo->pReverseChannel, (char*) pData, remain, &written, &pGError);
776 SysTryCatch(NID_IO, pGError == null, , E_SYSTEM, "[E_SYSTEM] Error occurred during writing message to socket.");
782 g_io_channel_flush(pClientInfo->pReverseChannel, &pGError);
794 _IpcServer::SendResponse(int client, const IPC::Message& message)
796 result r = E_SUCCESS;
800 GError* pGError = null;
801 _ClientInfo* pClientInfo = null;
803 SysTryReturn(NID_IO, client >= 0, false, E_INVALID_ARG, "[E_INVALID_ARG] clinet(%d) < 0", client);
804 SysTryCatch(NID_IO, !message.is_sync(), r = E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] Can't send sync. messagee.");
806 pClientInfo = __clients[client];
807 SysTryCatch(NID_IO, pClientInfo != null, r = E_INVALID_ARG, E_INVALID_ARG,
808 "[E_INVALID_ARG] client(%d) has not been registered.",
811 pData = (char*) message.data();
812 remain = message.size();
817 g_io_channel_write_chars(pClientInfo->pReverseChannel, (char*) pData, remain, &written, &pGError);
818 SysTryCatch(NID_IO, pGError == null, , E_SYSTEM, "[E_SYSTEM] Error occurred during writing message to socket.");
824 g_io_channel_flush(pClientInfo->pReverseChannel, &pGError);