2 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 // Licensed under the Apache License, Version 2.0 (the License);
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://www.apache.org/licenses/LICENSE-2.0
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
18 * @file FIo_IpcServer.cpp
19 * @brief This is the implementation file for the _IpcServer class.
31 #include <sys/types.h>
32 #include <sys/socket.h>
38 #include <ipc/ipc_message.h>
40 #include <FBaseRtMutex.h>
41 #include <FBaseSysLog.h>
42 #include <FBase_StringConverter.h>
43 #include <FBaseRt_EventDispatcher.h>
45 #include "FIo_IIpcServerEventListener.h"
46 #include "FIo_IpcServer.h"
50 using namespace Tizen::Base;
51 using namespace Tizen::Base::Runtime;
52 using namespace Tizen::App;
54 namespace Tizen { namespace Io
57 _IpcServer::_ChannelInfo::_ChannelInfo(void)
66 _IpcServer::_ChannelInfo::~_ChannelInfo(void)
68 if (pGIOChannel != null)
70 g_io_channel_unref(pGIOChannel);
77 g_source_destroy(pGSource);
80 g_source_unref(pGSource);
84 _IpcServer::_ClientInfo::_ClientInfo(void)
87 , pReverseChannel(null)
92 _IpcServer::_ClientInfo::~_ClientInfo(void)
94 if (pReverseChannel != null)
96 g_io_channel_unref(pReverseChannel);
102 _IpcServer::_IpcServer(void)
103 : __runOnCallerThread(false)
104 , __pEventDispatcher(null)
107 , __pHandlerGMainContext(null)
108 , __pHandlerGMainLoop(null)
109 , __pConnectGSource(null)
110 , __pCurrentChannel(null)
111 , __pCurrentClientInfo(null)
113 __messageBuffer[0] = '\0';
117 _IpcServer::~_IpcServer(void)
119 if (__pConnectGSource != null)
121 g_source_destroy(__pConnectGSource);
122 g_source_unref(__pConnectGSource);
123 __pConnectGSource = null;
126 if (!__runOnCallerThread)
128 if (__pEventDispatcher)
130 delete __pEventDispatcher;
131 __pEventDispatcher = null;
134 if (__pHandlerGMainLoop)
136 g_main_loop_unref(__pHandlerGMainLoop);
137 __pHandlerGMainLoop = null;
140 if (__pHandlerGMainContext)
142 g_main_context_unref(__pHandlerGMainContext);
143 __pHandlerGMainContext = null;
152 _IpcServer::Construct(const String& name, const _IIpcServerEventListener& listener, bool runOnCallerThread)
154 result r = E_SUCCESS;
156 GIOChannel* pGIOChannel = null;
157 GSource* pGSource = null;
159 struct sockaddr_un serverAddress;
160 int serverSocket = -1;
163 std::string socketName;
165 size_t socketNameLength = 0;
168 __pListener = const_cast <_IIpcServerEventListener*>(&listener);
169 __runOnCallerThread = runOnCallerThread;
171 pName = _StringConverter::CopyToCharArrayN(name);
172 SysTryReturnResult(NID_IO, pName != null, E_OUT_OF_MEMORY, "Not enough memory");
174 socketName.append("/var/run/osp/");
175 socketName.append(pName);
179 socketNameLength = socketName.size() + 1;
180 SysTryReturnResult(NID_IO, socketNameLength < 108, E_INVALID_ARG, "Server name is too long");
182 if (!__runOnCallerThread)
184 __pHandlerGMainContext = g_main_context_new();
185 __pHandlerGMainLoop = g_main_loop_new(__pHandlerGMainContext, FALSE);
190 __pHandlerGMainContext = g_main_context_get_thread_default();
191 if (__pHandlerGMainContext == null) // is global?
193 __pHandlerGMainContext = g_main_context_default();
194 if (__pHandlerGMainContext == null)
201 ret = unlink(socketName.c_str());
202 SysTryLog(NID_IO, ret == 0, "Unlink a socket has failed.. but it is not a problem.");
204 serverSocket = socket(AF_UNIX, SOCK_STREAM, 0);
205 SysTryReturnResult(NID_IO, serverSocket != -1, E_SYSTEM, "Failed to create a socket.");
207 bzero(&serverAddress, sizeof(serverAddress));
208 serverAddress.sun_family = AF_UNIX;
209 strncpy(serverAddress.sun_path, socketName.c_str(), socketNameLength);
210 serverLen = sizeof(serverAddress);
212 ret = bind(serverSocket, (const struct sockaddr*) &serverAddress, serverLen);
213 SysTryCatch(NID_IO, ret != -1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to bind a socket(%d, %s): %s", serverSocket,
214 socketName.c_str(), strerror(errno));
216 ret = chmod(socketName.c_str(), 0666);
217 SysTryCatch(NID_IO, ret == 0, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to change permission of a socket(%d, %s): %s", serverSocket,
218 socketName.c_str(), strerror(errno));
220 ret = listen(serverSocket, 128);
221 SysTryCatch(NID_IO, ret == 0, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to listen the socket(%d, %s): %s", serverSocket,
222 socketName.c_str(), strerror(errno));
224 pGIOChannel = g_io_channel_unix_new(serverSocket);
225 SysTryCatch(NID_IO, pGIOChannel != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Not enough memory.");
227 // socket will be closed when pGIOChannel is deleted.
228 g_io_channel_set_close_on_unref(pGIOChannel, TRUE);
231 pGSource = g_io_create_watch(pGIOChannel, (GIOCondition) (G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP));
232 SysTryCatch(NID_IO, pGSource != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
233 "[E_OUT_OF_MEMORY] Failed to create watch for socket.");
235 // channel will be delete when pGSource is deleted.
236 g_io_channel_unref(pGIOChannel);
239 g_source_set_callback(pGSource, (GSourceFunc) OnConnectionRequest, this, NULL);
240 g_source_attach(pGSource, __pHandlerGMainContext);
242 if (__runOnCallerThread)
244 __pListener->OnIpcServerStarted(*this);
248 ret = pthread_create(&__handlerThread, null, &ThreadProc, (void*) this);
249 SysTryCatch(NID_IO, ret == 0, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to an IPC thread");
252 __pConnectGSource = pGSource;
259 if (pGIOChannel != null)
261 g_io_channel_unref(pGIOChannel);
264 if (serverSocket != -1)
269 if (runOnCallerThread && __pHandlerGMainContext)
271 g_main_context_unref(__pHandlerGMainContext);
272 __pHandlerGMainContext = null;
280 int reverse; // if the connection is for reverse message
284 _IpcServer::OnConnectionRequest(GIOChannel* source, GIOCondition condition, gpointer data)
286 _IpcServer* pIpcServer = (_IpcServer*) data;
287 GError* pGError = null;
288 HelloMessage helloMessage;
289 _ClientInfo* pClientInfo = null;
290 _ChannelInfo* pChannelInfo = null;
291 GSource* pGSource = null;
292 GIOChannel* pChannel = null;
293 ssize_t readBytes = 0;
298 struct sockaddr_un clientAddress;
299 socklen_t clientLen = sizeof(clientAddress);
302 socklen_t ucredLen = sizeof(cr);
304 SysAssertf(pIpcServer != null, "Not yet constructed. Construct() should be called before use.\n");
305 SysAssertf(pIpcServer->__pListener != null, "Listener is null.\n");
307 server = g_io_channel_unix_get_fd(source);
309 client = accept(server, (struct sockaddr*) &clientAddress, &clientLen);
310 SysTryCatch(NID_IO, client != -1, , E_SYSTEM, "[E_SYSTEM] Accept failed.");
312 readBytes = read(client, &helloMessage, sizeof(helloMessage));
313 SysTryCatch(NID_IO, readBytes >= 0, , E_SYSTEM, "[E_SYSTEM] Failed to receive hello message (%d, %s).",
314 errno, strerror(errno));
316 pChannel = g_io_channel_unix_new(client);
317 SysTryCatch(NID_IO, pChannel != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Not enough memory.");
319 g_io_channel_set_encoding(pChannel, NULL, &pGError);
320 g_io_channel_set_flags(pChannel, G_IO_FLAG_NONBLOCK, &pGError);
322 g_io_channel_set_close_on_unref(pChannel, TRUE);
324 ret = getsockopt(client, SOL_SOCKET, SO_PEERCRED, &cr, &ucredLen);
325 SysTryCatch(NID_IO, ret >= 0, , E_SYSTEM, "[E_SYSTEM] Failed to get peercred information: %s", strerror(errno));
329 pClientInfo = pIpcServer->__clients[cr.pid];
330 if (pClientInfo == null) // first connection request from this client
332 pClientInfo = new (std::nothrow) _ClientInfo;
333 SysTryCatch(NID_IO, pClientInfo != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Not enough memory.");
335 pClientInfo->pIpcServer = pIpcServer;
336 pClientInfo->clientId = cr.pid;
338 char buffer[256] = {0, };
339 ret = aul_app_get_appid_bypid(cr.pid, buffer, sizeof(buffer));
340 SysTryCatch(NID_IO, ret == AUL_R_OK, delete pClientInfo, E_SYSTEM, "[E_SYSTEM] Failed to get the application ID of pid: %d", ret);
342 pClientInfo->appId = buffer;
344 pClientInfo->pReverseChannel = null;
346 pIpcServer->__clients[cr.pid] = pClientInfo;
347 pIpcServer->__pCurrentClientInfo = pClientInfo;
348 pIpcServer->__pListener->OnIpcClientConnected(*pIpcServer, cr.pid);
349 pIpcServer->__pCurrentClientInfo = null;
352 if (helloMessage.reverse != 0)
354 pClientInfo->pReverseChannel = pChannel;
358 pChannelInfo = new (std::nothrow) _ChannelInfo;
359 SysTryCatch(NID_IO, pChannelInfo != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Not enough memory.");
361 pGSource = g_io_create_watch(pChannel, (GIOCondition) (G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP));
362 g_source_set_callback(pGSource, (GSourceFunc) OnReadMessage, pChannelInfo, NULL);
363 g_source_attach(pGSource, pIpcServer->__pHandlerGMainContext);
365 pChannelInfo->pClientInfo = pClientInfo;
366 pChannelInfo->pGIOChannel = pChannel;
367 pChannelInfo->pGSource = pGSource;
369 pClientInfo->channels.push_back(pChannelInfo);
375 if (pChannel != null)
377 g_io_channel_unref(pChannel);
389 _IpcServer::GetClientId(void) const
391 if (__pCurrentClientInfo)
393 return __pCurrentClientInfo->clientId;
400 _IpcServer::GetClientPackageId(void) const
402 static String nullString;
404 if (__pCurrentClientInfo)
407 __pCurrentClientInfo->appId.SubString(0, 10, pkgId);
416 _IpcServer::GetClientApplicationId(void) const
418 static String nullString;
420 if (__pCurrentClientInfo)
422 return __pCurrentClientInfo->appId;
429 _IpcServer::HandleReceivedMessage(GIOChannel* source, GIOCondition condition, gpointer data)
431 GError* pGError = NULL;
433 IPC::Message* pMessage = NULL;
434 _ChannelInfo* pChannelInfo = (_ChannelInfo*) data;
435 _ClientInfo* pClientInfo = pChannelInfo->pClientInfo;
437 if (condition & G_IO_HUP)
439 SysLog(NID_IO, "G_IO_HUP, the connection is closed.");
441 int clientId = pClientInfo->clientId;
443 g_io_channel_shutdown(source, FALSE, &pGError);
445 for (unsigned int i = 0; i < pClientInfo->channels.size(); i++)
447 if (pChannelInfo == pClientInfo->channels[i])
449 pClientInfo->channels.erase(pClientInfo->channels.begin() + i);
451 // Do not destroy a source in a dispatch callback
452 // because main loop will do it if the callback return FALSE.
453 pChannelInfo->destroySource = false;
460 if (pClientInfo->channels.size() == 0)
462 SysLog(NID_IO, "All connections of client(%d) are closed. delete client info", clientId);
464 __pListener->OnIpcClientDisconnected(*this, clientId);
466 __clients[clientId] = null;
473 else if (condition & G_IO_IN)
476 const char* pStart = NULL;
477 const char* pEnd = NULL;
478 const char* pEndOfMessage = NULL;
483 status = g_io_channel_read_chars(source, (char*) __messageBuffer, __MAX_MESSAGE_BUFFER_SIZE, &readSize, &pGError);
484 if (status != G_IO_STATUS_NORMAL)
486 if (status == G_IO_STATUS_EOF || status == G_IO_STATUS_ERROR)
488 if (status == G_IO_STATUS_EOF)
490 SysLog(NID_IO, "G_IO_STATUS_EOF, the connection is closed.");
494 SysLog(NID_IO, "G_IO_STATUS_ERROR, the connection is closed. ");
498 g_io_channel_shutdown(source, FALSE, &pGError);
500 int clientId = pClientInfo->clientId;
502 for (unsigned int i = 0; i < pClientInfo->channels.size(); i++)
504 if (pChannelInfo == pClientInfo->channels[i])
506 pClientInfo->channels.erase(pClientInfo->channels.begin() + i);
508 pChannelInfo->destroySource = false;
514 if (pClientInfo->channels.size() == 0)
516 SysLog(NID_IO, "All connections of client(%d) are closed normally by the client.", clientId);
520 __pListener->OnIpcClientDisconnected(*this, clientId);
523 __clients[clientId] = null;
537 if (__pending.empty())
539 pStart = __messageBuffer;
540 pEnd = pStart + readSize;
544 __pending.append(__messageBuffer, readSize);
545 pStart = __pending.data();
546 pEnd = pStart + __pending.size();
551 pEndOfMessage = IPC::Message::FindNext(pStart, pEnd);
552 if (pEndOfMessage == NULL)
554 __pending.assign(pStart, pEnd - pStart);
558 pMessage = new (std::nothrow) IPC::Message(pStart, pEndOfMessage - pStart);
559 SysTryReturn(NID_IO, pMessage != null, FALSE, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
561 __pCurrentChannel = source;
565 __pListener->OnIpcRequestReceived(*this, *pMessage);
570 __pCurrentChannel = NULL;
572 pStart = pEndOfMessage;
585 _IpcServer::OnReadMessage(GIOChannel* source, GIOCondition condition, gpointer data)
587 gboolean ret = FALSE;
588 _ChannelInfo* pChannelInfo = (_ChannelInfo*) data;
589 _ClientInfo* pClientInfo = pChannelInfo->pClientInfo;
590 _IpcServer* pIpcServer = (_IpcServer*) pClientInfo->pIpcServer;
592 pIpcServer->__pCurrentClientInfo = pClientInfo;
593 ret = pIpcServer->HandleReceivedMessage(source, condition, data);
594 pIpcServer->__pCurrentClientInfo = null;
600 _IpcServer::ThreadProc(void* pParam)
602 _IpcServer* pIpcServer = (_IpcServer*) pParam;
603 if (pIpcServer != NULL)
605 pIpcServer->Run(NULL);
612 _IpcServer::Run(void* pParam)
614 result r = E_SUCCESS;
616 if (__pListener == null)
621 __pEventDispatcher = new (std::nothrow) _EventDispatcher;
622 SysTryReturnVoidResult(NID_IO, __pEventDispatcher != null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
624 r = __pEventDispatcher->Construct(__pHandlerGMainContext);
627 delete __pEventDispatcher;
628 __pEventDispatcher = null;
631 __pListener->OnIpcServerStarted(*this);
633 g_main_loop_run(__pHandlerGMainLoop);
635 __pListener->OnIpcServerStopped(*this);
639 _IpcServer::Start(void)
645 _IpcServer::GetName(void) const
651 _IpcServer::Stop(void)
653 result r = E_SUCCESS;
656 SysTryReturnResult(NID_IO, __pListener != null, E_SYSTEM, "Listener is null.");
658 if (!__runOnCallerThread)
660 pthread_t self = pthread_self();
662 if (__pHandlerGMainLoop)
664 g_main_loop_quit(__pHandlerGMainLoop);
667 if (__handlerThread != self)
669 ret = pthread_join(__handlerThread, null);
670 SysTryLog(NID_IO, ret == 0, "Join an IPC thread returns an error");
675 __pListener->OnIpcServerStopped(*this);
682 _IpcServer::Send(IPC::Message* msg)
687 GError* pGError = NULL;
690 pData = (char*) msg->data();
691 remain = msg->size();
698 g_io_channel_write_chars(__pCurrentChannel, (char*) pData, remain, &written, &pGError);
704 g_io_channel_flush(__pCurrentChannel, &pGError);
717 _IpcServer::SendResponse(int client, IPC::Message* pMessage)
719 result r = E_SUCCESS;
723 GError* pGError = null;
724 _ClientInfo* pClientInfo = null;
727 SysTryReturn(NID_IO, client >= 0 && pMessage != null, false, E_INVALID_ARG,
728 "[E_INVALID_ARG] pMessage(0x%x) is null or clinet(%d) < 0", pMessage,
730 SysTryCatch(NID_IO, !pMessage->is_sync(), r = E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] Can't send sync. messagee.");
732 pClientInfo = __clients[client];
733 SysTryCatch(NID_IO, pClientInfo != null, r = E_INVALID_ARG, E_INVALID_ARG,
734 "[E_INVALID_ARG] client(%d) has not been registered.",
737 pData = (char*) pMessage->data();
738 remain = pMessage->size();
743 ret = g_io_channel_write_chars(pClientInfo->pReverseChannel, (char*) pData, remain, &written, &pGError);
744 if (ret != G_IO_STATUS_NORMAL)
746 SysTryCatch(NID_IO, ret != G_IO_STATUS_AGAIN, , E_RESOURCE_UNAVAILABLE, "[E_RESOURCE_UNAVAILABLE] The socket buffer is full.");
748 SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Failed to send a response: %d", ret);
752 SysLog(NID_IO, "GError is %s", pGError->message);
763 g_io_channel_flush(pClientInfo->pReverseChannel, &pGError);
775 _IpcServer::SendResponse(int client, const IPC::Message& message)
777 result r = E_SUCCESS;
781 GError* pGError = null;
782 _ClientInfo* pClientInfo = null;
785 SysTryReturn(NID_IO, client >= 0, false, E_INVALID_ARG, "[E_INVALID_ARG] clinet(%d) < 0", client);
786 SysTryCatch(NID_IO, !message.is_sync(), r = E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] Can't send sync. messagee.");
788 pClientInfo = __clients[client];
789 SysTryCatch(NID_IO, pClientInfo != null, r = E_INVALID_ARG, E_INVALID_ARG,
790 "[E_INVALID_ARG] client(%d) has not been registered.",
793 pData = (char*) message.data();
794 remain = message.size();
799 ret = g_io_channel_write_chars(pClientInfo->pReverseChannel, (char*) pData, remain, &written, &pGError);
800 if (ret != G_IO_STATUS_NORMAL)
802 SysTryCatch(NID_IO, ret != G_IO_STATUS_AGAIN, , E_RESOURCE_UNAVAILABLE, "[E_RESOURCE_UNAVAILABLE] The socket buffer is full.");
804 SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Failed to send a response: %d", ret);
808 SysLog(NID_IO, "GError is %s", pGError->message);
818 g_io_channel_flush(pClientInfo->pReverseChannel, &pGError);