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 <sys/smack.h>
39 #include <ipc/ipc_message.h>
41 #include <FBaseRtMutex.h>
42 #include <FBaseSysLog.h>
43 #include <FBase_StringConverter.h>
44 #include <FBaseRt_EventDispatcher.h>
46 #include "IIpcServerEventListener.h"
47 #include "IpcServer.h"
52 using namespace Tizen::Base;
53 using namespace Tizen::Base::Runtime;
54 using namespace Tizen::App;
56 IpcServer::_ChannelInfo::_ChannelInfo(void)
65 IpcServer::_ChannelInfo::~_ChannelInfo(void)
67 if (pGIOChannel != null)
69 g_io_channel_unref(pGIOChannel);
76 g_source_destroy(pGSource);
79 g_source_unref(pGSource);
83 IpcServer::_ClientInfo::_ClientInfo(void)
86 , pReverseChannel(null)
91 IpcServer::_ClientInfo::~_ClientInfo(void)
93 if (pReverseChannel != null)
95 g_io_channel_unref(pReverseChannel);
101 IpcServer::IpcServer(void)
102 : __runOnCallerThread(false)
103 , __pEventDispatcher(null)
106 , __pHandlerGMainContext(null)
107 , __pHandlerGMainLoop(null)
108 , __pConnectGSource(null)
109 , __pCurrentChannel(null)
110 , __pCurrentClientInfo(null)
112 __messageBuffer[0] = '\0';
116 IpcServer::~IpcServer(void)
118 if (__pConnectGSource != null)
120 g_source_destroy(__pConnectGSource);
121 g_source_unref(__pConnectGSource);
122 __pConnectGSource = null;
125 if (!__runOnCallerThread)
127 if (__pEventDispatcher)
129 delete __pEventDispatcher;
130 __pEventDispatcher = null;
133 if (__pHandlerGMainLoop)
135 g_main_loop_unref(__pHandlerGMainLoop);
136 __pHandlerGMainLoop = null;
139 if (__pHandlerGMainContext)
141 g_main_context_unref(__pHandlerGMainContext);
142 __pHandlerGMainContext = null;
151 IpcServer::Construct(const String& name, const IIpcServerEventListener& listener, bool runOnCallerThread)
153 result r = E_SUCCESS;
155 GIOChannel* pGIOChannel = null;
156 GSource* pGSource = null;
158 struct sockaddr_un serverAddress;
159 int serverSocket = -1;
162 std::string socketName;
164 size_t socketNameLength = 0;
167 __pListener = const_cast <IIpcServerEventListener*>(&listener);
168 __runOnCallerThread = runOnCallerThread;
170 pName = _StringConverter::CopyToCharArrayN(name);
171 SysTryReturnResult(NID_IO, pName != null, E_OUT_OF_MEMORY, "Not enough memory");
173 socketName.append("/tmp/");
174 socketName.append(pName);
178 socketNameLength = socketName.size() + 1;
179 SysTryReturnResult(NID_IO, socketNameLength < 108, E_INVALID_ARG, "Server name is too long");
181 if (!__runOnCallerThread)
183 __pHandlerGMainContext = g_main_context_new();
184 __pHandlerGMainLoop = g_main_loop_new(__pHandlerGMainContext, FALSE);
189 __pHandlerGMainContext = g_main_context_get_thread_default();
190 if (__pHandlerGMainContext == null) // is global?
192 __pHandlerGMainContext = g_main_context_default();
193 if (__pHandlerGMainContext == null)
200 ret = unlink(socketName.c_str());
201 SysTryLog(NID_IO, ret == 0, "Unlink a socket has failed.. but it is not a problem.");
203 serverSocket = socket(AF_UNIX, SOCK_STREAM, 0);
204 SysTryReturnResult(NID_IO, serverSocket != -1, E_SYSTEM, "Failed to create a socket.");
206 // SMACK (Add a * label to socket)
207 if(smack_fsetlabel(serverSocket, "@", SMACK_LABEL_IPOUT) != 0)
209 SysTryCatch(NID_IO, errno == EOPNOTSUPP, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] SMACK labeling failed");
210 SysLog(NID_IO, "Kernel doesn't have Smack.");
213 if(smack_fsetlabel(serverSocket, "*", SMACK_LABEL_IPIN) != 0)
215 SysTryCatch(NID_IO, errno == EOPNOTSUPP, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] SMACK labeling failed");
216 SysLog(NID_IO, "Kernel doesn't have Smack.");
219 bzero(&serverAddress, sizeof(serverAddress));
220 serverAddress.sun_family = AF_UNIX;
221 strncpy(serverAddress.sun_path, socketName.c_str(), socketNameLength);
222 serverLen = sizeof(serverAddress);
224 ret = bind(serverSocket, (const struct sockaddr*) &serverAddress, serverLen);
225 SysTryCatch(NID_IO, ret != -1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to bind a socket(%d, %s): %s", serverSocket,
226 socketName.c_str(), strerror(errno));
228 ret = chmod(socketName.c_str(), 0666);
229 SysTryCatch(NID_IO, ret == 0, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to change permission of a socket(%d, %s): %s", serverSocket,
230 socketName.c_str(), strerror(errno));
232 listen(serverSocket, 15);
234 pGIOChannel = g_io_channel_unix_new(serverSocket);
235 SysTryCatch(NID_IO, pGIOChannel != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Not enough memory.");
237 // socket will be closed when pGIOChannel is deleted.
238 g_io_channel_set_close_on_unref(pGIOChannel, TRUE);
241 pGSource = g_io_create_watch(pGIOChannel, (GIOCondition) (G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP));
242 SysTryCatch(NID_IO, pGSource != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
243 "[E_OUT_OF_MEMORY] Failed to create watch for socket.");
245 // channel will be delete when pGSource is deleted.
246 g_io_channel_unref(pGIOChannel);
249 g_source_set_callback(pGSource, (GSourceFunc) OnConnectionRequest, this, NULL);
250 g_source_attach(pGSource, __pHandlerGMainContext);
252 if (__runOnCallerThread)
254 __pListener->OnIpcServerStarted(*this);
258 ret = pthread_create(&__handlerThread, null, &ThreadProc, (void*) this);
259 SysTryCatch(NID_IO, ret == 0, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to an IPC thread");
262 __pConnectGSource = pGSource;
267 if (pGIOChannel != null)
269 g_io_channel_unref(pGIOChannel);
272 if (serverSocket != -1)
277 if (runOnCallerThread && __pHandlerGMainContext)
279 g_main_context_unref(__pHandlerGMainContext);
280 __pHandlerGMainContext = null;
289 bool reverse; // true if the connection is for reverse message
294 IpcServer::OnConnectionRequest(GIOChannel* source, GIOCondition condition, gpointer data)
296 IpcServer* pIpcServer = (IpcServer*) data;
297 GError* pGError = null;
298 HelloMessage helloMessage;
299 _ClientInfo* pClientInfo = null;
300 _ChannelInfo* pChannelInfo = null;
301 GSource* pGSource = null;
302 GIOChannel* pChannel = null;
306 struct sockaddr_un clientAddress;
307 socklen_t clientLen = sizeof(clientAddress);
309 SysAssertf(pIpcServer != null, "Not yet constructed. Construct() should be called before use.\n");
310 SysAssertf(pIpcServer->__pListener != null, "Listener is null.\n");
312 server = g_io_channel_unix_get_fd(source);
314 client = accept(server, (struct sockaddr*) &clientAddress, &clientLen);
315 SysTryCatch(NID_IO, client != -1, , E_SYSTEM, "[E_SYSTEM] Accept failed.");
317 read(client, &helloMessage, sizeof(helloMessage));
318 helloMessage.appId[255] = '\0';
320 pChannel = g_io_channel_unix_new(client);
321 SysTryCatch(NID_IO, pChannel != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Not enough memory.");
323 g_io_channel_set_encoding(pChannel, NULL, &pGError);
324 g_io_channel_set_flags(pChannel, G_IO_FLAG_NONBLOCK, &pGError);
326 g_io_channel_set_close_on_unref(pChannel, TRUE);
329 pClientInfo = pIpcServer->__clients[helloMessage.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 = helloMessage.pid;
337 pClientInfo->appId.Append((wchar_t*) helloMessage.appId);
338 pClientInfo->pReverseChannel = null;
340 pIpcServer->__clients[helloMessage.pid] = pClientInfo;
342 pIpcServer->__pCurrentClientInfo = pClientInfo;
343 pIpcServer->__pListener->OnIpcClientConnected(*pIpcServer, helloMessage.pid);
344 pIpcServer->__pCurrentClientInfo = null;
347 if (helloMessage.reverse)
349 pClientInfo->pReverseChannel = pChannel;
353 pChannelInfo = new (std::nothrow) _ChannelInfo;
354 SysTryCatch(NID_IO, pChannelInfo != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Not enough memory.");
356 pGSource = g_io_create_watch(pChannel, (GIOCondition) (G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP));
357 g_source_set_callback(pGSource, (GSourceFunc) OnReadMessage, pChannelInfo, NULL);
358 g_source_attach(pGSource, pIpcServer->__pHandlerGMainContext);
360 pChannelInfo->pClientInfo = pClientInfo;
361 pChannelInfo->pGIOChannel = pChannel;
362 pChannelInfo->pGSource = pGSource;
364 pClientInfo->channels.push_back(pChannelInfo);
370 if (pChannel != null)
372 g_io_channel_unref(pChannel);
384 IpcServer::GetClientId(void) const
386 if (__pCurrentClientInfo)
388 return __pCurrentClientInfo->clientId;
395 IpcServer::GetClientProcessId(void) const
397 if (__pCurrentClientInfo)
399 return __pCurrentClientInfo->clientId;
406 IpcServer::GetClientAppId(void) const
408 static String nullString;
410 if (__pCurrentClientInfo)
412 return __pCurrentClientInfo->appId;
419 IpcServer::GetClientAppExecutableName(void) const
421 static String nullString;
423 //if (__pCurrentClientInfo)
425 //return __pCurrentClientInfo->appExecutableName;
432 IpcServer::GetClientApplicationId(void) const
434 static String nullString;
436 if (__pCurrentClientInfo)
438 return __pCurrentClientInfo->appId;
445 IpcServer::HandleReceivedMessage(GIOChannel* source, GIOCondition condition, gpointer data)
447 GError* pGError = NULL;
449 IPC::Message* pMessage = NULL;
450 _ChannelInfo* pChannelInfo = (_ChannelInfo*) data;
451 _ClientInfo* pClientInfo = pChannelInfo->pClientInfo;
453 if (condition & G_IO_HUP)
455 SysLog(NID_IO, "Connection closed");
456 int clientId = pClientInfo->clientId;
458 g_io_channel_shutdown(source, FALSE, &pGError);
460 for (unsigned int i = 0; i < pClientInfo->channels.size(); i++)
462 if (pChannelInfo == pClientInfo->channels[i])
464 pClientInfo->channels.erase(pClientInfo->channels.begin() + i);
466 // Do not destroy a source in a dispatch callback
467 // because main loop will do it if the callback return FALSE.
468 pChannelInfo->destroySource = false;
475 if (pClientInfo->channels.size() == 0)
477 SysLog(NID_IO, "All connections of client(%d) are closed. delete client info", clientId);
479 __pListener->OnIpcClientDisconnected(*this, clientId);
481 __clients[clientId] = null;
488 else if (condition & G_IO_IN)
491 const char* pStart = NULL;
492 const char* pEnd = NULL;
493 const char* pEndOfMessage = NULL;
498 status = g_io_channel_read_chars(source, (char*) __messageBuffer, __MAX_MESSAGE_BUFFER_SIZE, &readSize, &pGError);
499 if (status != G_IO_STATUS_NORMAL)
501 if (status == G_IO_STATUS_EOF || status == G_IO_STATUS_ERROR)
503 if (status == G_IO_STATUS_EOF)
505 SysLog(NID_IO, "G_IO_STATUS_EOF, the connection is closed.");
509 SysLog(NID_IO, "G_IO_STATUS_ERROR, the connection is closed. ");
513 g_io_channel_shutdown(source, FALSE, &pGError);
515 int clientId = pClientInfo->clientId;
517 for (unsigned int i = 0; i < pClientInfo->channels.size(); i++)
519 if (pChannelInfo == pClientInfo->channels[i])
521 pClientInfo->channels.erase(pClientInfo->channels.begin() + i);
523 pChannelInfo->destroySource = false;
529 if (pClientInfo->channels.size() == 0)
531 SysLog(NID_IO, "All connections of client(%d) are closed normally by the client.", clientId);
535 __pListener->OnIpcClientDisconnected(*this, clientId);
538 __clients[clientId] = null;
552 if (__pending.empty())
554 pStart = __messageBuffer;
555 pEnd = pStart + readSize;
559 __pending.append(__messageBuffer, readSize);
560 pStart = __pending.data();
561 pEnd = pStart + __pending.size();
566 pEndOfMessage = IPC::Message::FindNext(pStart, pEnd);
567 if (pEndOfMessage == NULL)
569 __pending.assign(pStart, pEnd - pStart);
573 pMessage = new (std::nothrow) IPC::Message(pStart, pEndOfMessage - pStart);
574 SysTryReturn(NID_IO, pMessage != null, FALSE, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
576 __pCurrentChannel = source;
580 __pListener->OnIpcRequestReceived(*this, *pMessage);
585 __pCurrentChannel = NULL;
587 pStart = pEndOfMessage;
600 IpcServer::OnReadMessage(GIOChannel* source, GIOCondition condition, gpointer data)
602 gboolean ret = FALSE;
603 _ChannelInfo* pChannelInfo = (_ChannelInfo*) data;
604 _ClientInfo* pClientInfo = pChannelInfo->pClientInfo;
605 IpcServer* pIpcServer = (IpcServer*) pClientInfo->pIpcServer;
607 pIpcServer->__pCurrentClientInfo = pClientInfo;
608 ret = pIpcServer->HandleReceivedMessage(source, condition, data);
609 pIpcServer->__pCurrentClientInfo = null;
615 IpcServer::ThreadProc(void* pParam)
617 IpcServer* pIpcServer = (IpcServer*) pParam;
618 if (pIpcServer != NULL)
620 pIpcServer->Run(NULL);
627 IpcServer::Run(void* pParam)
629 result r = E_SUCCESS;
631 if (__pListener == null)
636 __pEventDispatcher = new (std::nothrow) _EventDispatcher;
637 SysTryReturnVoidResult(NID_IO, __pEventDispatcher != null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
639 r = __pEventDispatcher->Construct(__pHandlerGMainContext);
642 delete __pEventDispatcher;
643 __pEventDispatcher = null;
646 __pListener->OnIpcServerStarted(*this);
648 g_main_loop_run(__pHandlerGMainLoop);
650 __pListener->OnIpcServerStopped(*this);
654 IpcServer::Start(void)
660 IpcServer::GetName(void) const
666 IpcServer::Stop(void)
668 result r = E_SUCCESS;
671 SysTryReturnResult(NID_IO, __pListener != null, E_SYSTEM, "Listener is null.");
673 if (!__runOnCallerThread)
675 pthread_t self = pthread_self();
677 if (__pHandlerGMainLoop)
679 g_main_loop_quit(__pHandlerGMainLoop);
682 if (__handlerThread != self)
684 ret = pthread_join(__handlerThread, null);
685 SysTryLog(NID_IO, ret == 0, "Join an IPC thread returns an error");
690 __pListener->OnIpcServerStopped(*this);
697 IpcServer::Send(IPC::Message* msg)
702 GError* pGError = NULL;
705 pData = (char*) msg->data();
706 remain = msg->size();
713 g_io_channel_write_chars(__pCurrentChannel, (char*) pData, remain, &written, &pGError);
719 g_io_channel_flush(__pCurrentChannel, &pGError);
730 IpcServer::SendResponse(int client, IPC::Message* pMessage)
732 result r = E_SUCCESS;
736 GError* pGError = null;
737 _ClientInfo* pClientInfo = null;
739 SysTryReturn(NID_IO, client >= 0 && pMessage != null, false, E_INVALID_ARG,
740 "[E_INVALID_ARG] pMessage(0x%x) is null or clinet(%d) < 0", pMessage,
742 SysTryCatch(NID_IO, !pMessage->is_sync(), r = E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] Can't send sync. messagee.");
744 pClientInfo = __clients[client];
745 SysTryCatch(NID_IO, pClientInfo != null, r = E_INVALID_ARG, E_INVALID_ARG,
746 "[E_INVALID_ARG] client(%d) has not been registered.",
749 pData = (char*) pMessage->data();
750 remain = pMessage->size();
755 g_io_channel_write_chars(pClientInfo->pReverseChannel, (char*) pData, remain, &written, &pGError);
756 SysTryCatch(NID_IO, pGError == null, , E_SYSTEM, "[E_SYSTEM] Error occurred during writing message to socket.");
762 g_io_channel_flush(pClientInfo->pReverseChannel, &pGError);
774 IpcServer::SendResponse(int client, const IPC::Message& message)
776 result r = E_SUCCESS;
780 GError* pGError = null;
781 _ClientInfo* pClientInfo = null;
783 SysTryReturn(NID_IO, client >= 0, false, E_INVALID_ARG, "[E_INVALID_ARG] clinet(%d) < 0", client);
784 SysTryCatch(NID_IO, !message.is_sync(), r = E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] Can't send sync. messagee.");
786 pClientInfo = __clients[client];
787 SysTryCatch(NID_IO, pClientInfo != null, r = E_INVALID_ARG, E_INVALID_ARG,
788 "[E_INVALID_ARG] client(%d) has not been registered.",
791 pData = (char*) message.data();
792 remain = message.size();
797 g_io_channel_write_chars(pClientInfo->pReverseChannel, (char*) pData, remain, &written, &pGError);
798 SysTryCatch(NID_IO, pGError == null, , E_SYSTEM, "[E_SYSTEM] Error occurred during writing message to socket.");
804 g_io_channel_flush(pClientInfo->pReverseChannel, &pGError);