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_IpcClient.cpp
20 * @brief This is the implementation file for the _IpcClient class.
26 #include <sys/types.h>
27 #include <sys/socket.h>
40 #include <FBaseRtMutex.h>
41 #include <FApp_AppInfo.h>
42 #include <FAppPkg_PackageManagerImpl.h>
43 #include <FBaseSysLog.h>
44 #include <FBase_StringConverter.h>
45 #include "FIo_IpcClient.h"
46 #include "FIo_IIpcClientEventListener.h"
50 using namespace Tizen::App;
51 using namespace Tizen::App::Package;
52 using namespace Tizen::Base;
53 using namespace Tizen::Base::Runtime;
55 namespace Tizen { namespace Io
58 _IpcClient::_IpcClient(void)
59 : __pReverseSource(null)
64 __messageBuffer[0] = '\0';
67 _IpcClient::~_IpcClient(void)
71 if (__pReverseSource != null)
73 g_source_destroy(__pReverseSource);
74 g_source_unref(__pReverseSource);
75 __pReverseSource = null;
78 while (__fds.size() > 0)
90 _IpcClient::Construct(const String& name, const _IIpcClientEventListener* pListener)
92 SysAssertf(__pFdLock == null, "Already constructed. Calling Construct() twice or more on a same instance is not allowed for this class.");
97 __pListener = const_cast <_IIpcClientEventListener*>(pListener);
99 pMutex = new (std::nothrow) Mutex();
100 SysTryReturnResult(NID_IO, pMutex != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
102 r = pMutex->Create();
103 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to create SourceLock.", GetErrorMessage(r));
107 r = MakeConnection();
108 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to connect to server.", GetErrorMessage(r));
112 r = MakeConnection(true);
113 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to connect to server.", GetErrorMessage(r));
129 _IpcClient::GetName(void) const
139 char appExecutableName[256];
143 _IpcClient::MakeConnection(bool forReverse)
145 result r = E_SUCCESS;
147 struct sockaddr_un server;
148 socklen_t serverLen = 0;
151 HelloMessage helloMessage = {0, false};
152 std::string socketName;
153 char* pSocketName = null;
154 size_t socketNameLength = 0;
157 helloMessage.pid = getpid();
158 helloMessage.reverse = forReverse;
160 pSocketName = _StringConverter::CopyToCharArrayN(__name);
161 SysTryReturnResult(NID_IO, pSocketName != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
163 socketName.append("/tmp/");
164 socketName.append(pSocketName);
166 delete[] pSocketName;
168 socketNameLength = socketName.size() + 1;
169 SysTryReturnResult(NID_IO, socketNameLength < 108, E_INVALID_ARG, "Server name is too long.");
174 String pkgId = _AppInfo::GetPackageId();
175 int length = (pkgId.GetLength() + 1) * sizeof(wchar_t);
181 SysTryReturnResult(NID_IO, pkgId.GetLength() > 0, E_SYSTEM, "AppId dose not exist.");
183 memcpy(helloMessage.pkgId, pkgId.GetPointer(), length);
185 // Set an executableName
186 String appExecutableName = _AppInfo::GetAppExecutableName();
187 length = (appExecutableName.GetLength() + 1) * sizeof(wchar_t);
193 if (appExecutableName.GetLength() != 0)
195 memcpy(helloMessage.appExecutableName, appExecutableName.GetPointer(), length);
199 client = socket(AF_UNIX, SOCK_STREAM, 0);
200 SysTryCatch(NID_IO, client != -1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to create a socket : %s.", strerror(errno));
202 flags = fcntl(client, F_GETFL, 0);
203 ret = fcntl(client, F_SETFL, flags | O_NONBLOCK);
204 SysTryCatch(NID_IO, ret >= 0 , r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to set file status flags (%d, %s).",
205 errno, strerror(errno));
207 bzero(&server, sizeof(server));
208 server.sun_family = AF_UNIX;
209 strncpy(server.sun_path, socketName.c_str(), socketNameLength);
210 serverLen = sizeof(server);
212 ret = connect(client, (struct sockaddr*) &server, serverLen);
215 SysTryCatch(NID_IO, errno == EINPROGRESS, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to connect to server(%s) : %s",
216 socketName.c_str(), strerror(errno));
220 struct timeval timeout;
223 socklen_t socketLength = 0;
226 FD_SET(client, &rset);
233 ret = select(client+1, &rset, &wset, NULL, &timeout);
236 SysTryCatch(NID_IO, errno == EINTR , r = E_SYSTEM, E_SYSTEM, "[E_TIMEOUT] Failed to connect due to system error.");
243 SysLogException(NID_IO, E_TIMEOUT, "[E_TIMEOUT] Failed to connect due to timeout.");
252 if (FD_ISSET(client, &rset) || FD_ISSET(client, &wset))
254 length = sizeof(error);
255 ret = getsockopt(client, SOL_SOCKET, SO_ERROR, &error, &socketLength);
256 SysTryCatch(NID_IO, ret >= 0 , r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to connect to server(%s) : %s",
257 socketName.c_str(), strerror(errno));
262 SysLogException(NID_IO, E_SYSTEM, "[E_TIMEOUT] Failed to connect due to system error.");
267 ret = fcntl(client, F_SETFL, flags);
268 SysTryCatch(NID_IO, ret >= 0 , r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to set file status flags (%d, %s).",
269 errno, strerror(errno));
271 write(client, &helloMessage, sizeof(helloMessage));
275 GError* pGError = null;
276 GSource* pGSource = null;
278 GIOChannel* pChannel = g_io_channel_unix_new(client);
279 GMainContext* pGMainContext = g_main_context_default();
281 g_io_channel_set_encoding(pChannel, null, &pGError);
282 g_io_channel_set_flags(pChannel, G_IO_FLAG_NONBLOCK, &pGError);
283 g_io_channel_set_close_on_unref(pChannel, TRUE);
285 pGSource = g_io_create_watch(pChannel, (GIOCondition) (G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP));
286 g_source_set_callback(pGSource, (GSourceFunc) OnReadMessage, this, null);
287 g_source_attach(pGSource, pGMainContext);
289 g_io_channel_unref(pChannel);
290 __pReverseSource = pGSource;
311 _IpcClient::OnReadMessage(GIOChannel* source, GIOCondition condition, gpointer data)
314 _IpcClient* pIpcClient = (_IpcClient*) data;
316 return pIpcClient->HandleReceivedMessage(source, condition);
320 _IpcClient::HandleReceivedMessage(GIOChannel* source, GIOCondition condition)
322 GError* pGError = null;
324 IPC::Message* pMessage = null;
326 if (condition & G_IO_HUP)
328 SysLog(NID_IO, "G_IO_HUP, the connection is closed.");
330 g_source_destroy(__pReverseSource);
331 g_source_unref(__pReverseSource);
332 __pReverseSource = null;
336 __pListener->OnIpcServerDisconnected(*this);
341 else if (condition & G_IO_IN)
344 const char* pStart = null;
345 const char* pEnd = null;
346 const char* pEndOfMessage = null;
351 status = g_io_channel_read_chars(source, (char*) __messageBuffer, __MAX_MESSAGE_BUFFER_SIZE, &readSize, &pGError);
352 if (status == G_IO_STATUS_EOF || status == G_IO_STATUS_ERROR)
354 if (status == G_IO_STATUS_EOF)
356 SysLog(NID_IO, "G_IO_STATUS_EOF, the connection is closed.");
360 SysLog(NID_IO, "G_IO_STATUS_ERROR, the connection is closed. ");
365 g_io_channel_shutdown(source, FALSE, &pGError);
367 g_source_destroy(__pReverseSource);
368 g_source_unref(__pReverseSource);
369 __pReverseSource = null;
373 __pListener->OnIpcServerDisconnected(*this);
384 if (__pending.empty())
386 pStart = __messageBuffer;
387 pEnd = pStart + readSize;
391 __pending.append(__messageBuffer, readSize);
392 pStart = __pending.data();
393 pEnd = pStart + __pending.size();
398 pEndOfMessage = IPC::Message::FindNext(pStart, pEnd);
399 if (pEndOfMessage == null)
401 __pending.assign(pStart, pEnd - pStart);
405 pMessage = new (std::nothrow) IPC::Message(pStart, pEndOfMessage - pStart);
406 SysTryReturn(NID_IO, pMessage != null, FALSE, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
410 __pListener->OnIpcResponseReceived(*this, *pMessage);
415 pStart = pEndOfMessage;
428 _IpcClient::AcquireFd(void)
430 result r = E_SUCCESS;
435 __pFdLock->Acquire();
436 if (__fds.size() == 0)
438 __pFdLock->Release();
439 r = MakeConnection(false);
440 SysTryReturn(NID_IO, !IsFailed(r), -1, r, "[%s] Failed to connect to the server.", GetErrorMessage(r));
448 __pFdLock->Release();
455 _IpcClient::ReleaseFd(int fd)
457 __pFdLock->Acquire();
461 __pFdLock->Release();
465 _IpcClient::SendAsync(IPC::Message* pMessage)
467 result r = E_SUCCESS;
474 pData = (char*) pMessage->data();
475 remain = pMessage->size();
478 SysTryReturnResult(NID_IO, fd != -1, E_SYSTEM, "Failed to get fd.");
482 written = write(fd, (char*) pData, remain);
493 _IpcClient::SendSync(IPC::Message* pMessage)
495 result r = E_SUCCESS;
505 char* pEndOfMessage = null;
511 IPC::Message* pReply = null;
512 MessageReplyDeserializer* pReplyDeserializer = null;
513 IPC::SyncMessage* pSyncMessage = dynamic_cast <IPC::SyncMessage*>(pMessage);
514 SysTryReturnResult(NID_IO, pSyncMessage != null, E_INVALID_ARG, "pMessage is not a sync message.");
516 messageId = SyncMessage::GetMessageId(*pSyncMessage);
519 SysTryReturnResult(NID_IO, fd != -1, E_SYSTEM, "Failed to get fd.");
521 pData = (char*) pSyncMessage->data();
522 remain = pSyncMessage->size();
526 written = write(fd, (char*) pData, remain);
533 pfd.events = POLLIN | POLLRDHUP;
540 if (pfd.revents & POLLRDHUP)
545 if (pfd.revents & POLLIN)
547 readSize = read(fd, buffer, 1024);
550 message.append(buffer, readSize);
552 pEndOfMessage = (char*) IPC::Message::FindNext(message.data(), message.data() + message.size());
555 pReply = new (std::nothrow) IPC::Message(message.data(), pEndOfMessage - message.data());
556 SysTryReturnResult(NID_IO, pReply != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
561 pReplyDeserializer = pSyncMessage->GetReplyDeserializer();
562 pReplyDeserializer->SerializeOutputParameters(*pReply);
565 delete pReplyDeserializer;
573 _IpcClient::Send(IPC::Message* pMessage)
575 result r = E_SUCCESS;
577 SysAssertf(__pFdLock != null, "Not yet constructed. Construct() should be called before use.\n");
579 if (pMessage->is_sync())
581 r = SendSync(pMessage);
585 r = SendAsync(pMessage);
592 _IpcClient::SendRequest(IPC::Message* pMessage)
594 return Send(pMessage);
598 _IpcClient::SendRequest(const IPC::Message& message)
600 result r = E_SUCCESS;
602 SysAssertf(__pFdLock != null, "Not yet constructed. Construct() should be called before use.\n");
604 if (message.is_sync())
606 r = SendSync(const_cast<IPC::Message*>(&message));
610 r = SendAsync(const_cast<IPC::Message*>(&message));