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_IpcClient.cpp
19 * @brief This is the implementation file for the _IpcClient class.
25 #include <sys/types.h>
26 #include <sys/socket.h>
39 #include <FBaseRtMutex.h>
40 #include <FApp_AppInfo.h>
41 #include <FAppPkg_PackageManagerImpl.h>
42 #include <FBaseSysLog.h>
43 #include <FBase_StringConverter.h>
44 #include "FIo_IpcClient.h"
45 #include "FIo_IIpcClientEventListener.h"
49 using namespace Tizen::App;
50 using namespace Tizen::App::Package;
51 using namespace Tizen::Base;
52 using namespace Tizen::Base::Runtime;
54 namespace Tizen { namespace Io
57 _IpcClient::_IpcClient(void)
58 : __pReverseSource(null)
63 __messageBuffer[0] = '\0';
66 _IpcClient::~_IpcClient(void)
70 if (__pReverseSource != null)
72 g_source_destroy(__pReverseSource);
73 g_source_unref(__pReverseSource);
74 __pReverseSource = null;
77 while (__fds.size() > 0)
89 _IpcClient::Construct(const String& name, const _IIpcClientEventListener* pListener)
91 SysAssertf(__pFdLock == null, "Already constructed. Calling Construct() twice or more on a same instance is not allowed for this class.");
96 __pListener = const_cast <_IIpcClientEventListener*>(pListener);
98 pMutex = new (std::nothrow) Mutex();
99 SysTryReturnResult(NID_IO, pMutex != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
101 r = pMutex->Create();
102 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to create SourceLock.", GetErrorMessage(r));
106 r = MakeConnection();
107 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to connect to server.", GetErrorMessage(r));
111 r = MakeConnection(true);
112 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to connect to server.", GetErrorMessage(r));
128 _IpcClient::GetName(void) const
141 _IpcClient::MakeConnection(bool forReverse)
143 result r = E_SUCCESS;
145 struct sockaddr_un server;
146 socklen_t serverLen = 0;
150 HelloMessage helloMessage = {0, 0};
151 std::string socketName;
152 char* pSocketName = null;
153 size_t socketNameLength = 0;
156 helloMessage.pid = getpid();
159 helloMessage.reverse = 1;
163 helloMessage.reverse = 0;
166 pSocketName = _StringConverter::CopyToCharArrayN(__name);
167 SysTryReturnResult(NID_IO, pSocketName != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
169 socketName.append("/tmp/");
170 socketName.append(pSocketName);
172 delete[] pSocketName;
174 socketNameLength = socketName.size() + 1;
175 SysTryReturnResult(NID_IO, socketNameLength < 108, E_INVALID_ARG, "Server name is too long.");
180 String appId = _AppInfo::GetApplicationId();
181 int length = (appId.GetLength() + 1) * sizeof(wchar_t);
187 SysTryReturnResult(NID_IO, appId.GetLength() > 0, E_SYSTEM, "AppId dose not exist.");
189 memcpy(helloMessage.appId, appId.GetPointer(), length);
192 client = socket(AF_UNIX, SOCK_STREAM, 0);
193 SysTryCatch(NID_IO, client != -1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to create a socket : %s.", strerror(errno));
195 flags = fcntl(client, F_GETFL, 0);
196 ret = fcntl(client, F_SETFL, flags | O_NONBLOCK);
197 SysTryCatch(NID_IO, ret >= 0 , r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to set file status flags (%d, %s).",
198 errno, strerror(errno));
200 bzero(&server, sizeof(server));
201 server.sun_family = AF_UNIX;
202 strncpy(server.sun_path, socketName.c_str(), socketNameLength);
203 serverLen = sizeof(server);
205 // Retry if the server is not ready
209 ret = connect(client, (struct sockaddr*) &server, serverLen);
210 if (ret < 0 && errno == ENOENT)
212 SysLog(NID_IO, "The server is not ready. %d", retry);
226 SysTryCatch(NID_IO, errno == EINPROGRESS, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to connect to server(%s) : %s",
227 socketName.c_str(), strerror(errno));
231 struct timeval timeout;
234 socklen_t socketLength = 0;
237 FD_SET(client, &rset);
244 ret = select(client+1, &rset, &wset, NULL, &timeout);
247 SysTryCatch(NID_IO, errno == EINTR , r = E_SYSTEM, E_SYSTEM, "[E_TIMEOUT] Failed to connect due to system error.");
254 SysLogException(NID_IO, E_TIMEOUT, "[E_TIMEOUT] Failed to connect due to timeout.");
263 if (FD_ISSET(client, &rset) || FD_ISSET(client, &wset))
265 length = sizeof(error);
266 ret = getsockopt(client, SOL_SOCKET, SO_ERROR, &error, &socketLength);
267 SysTryCatch(NID_IO, ret >= 0 , r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to connect to server(%s) : %s",
268 socketName.c_str(), strerror(errno));
273 SysLogException(NID_IO, E_SYSTEM, "[E_TIMEOUT] Failed to connect due to system error.");
278 ret = fcntl(client, F_SETFL, flags);
279 SysTryCatch(NID_IO, ret >= 0, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to set file status flags (%d, %s).",
280 errno, strerror(errno));
282 ret = write(client, &helloMessage, sizeof(helloMessage));
283 SysTryCatch(NID_IO, ret >= 0, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to send hello message (%d, %s).",
284 errno, strerror(errno));
288 GError* pGError = null;
289 GSource* pGSource = null;
291 GIOChannel* pChannel = g_io_channel_unix_new(client);
292 GMainContext* pGMainContext = g_main_context_default();
294 g_io_channel_set_encoding(pChannel, null, &pGError);
295 g_io_channel_set_flags(pChannel, G_IO_FLAG_NONBLOCK, &pGError);
296 g_io_channel_set_close_on_unref(pChannel, TRUE);
298 pGSource = g_io_create_watch(pChannel, (GIOCondition) (G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP));
299 g_source_set_callback(pGSource, (GSourceFunc) OnReadMessage, this, null);
300 g_source_attach(pGSource, pGMainContext);
302 g_io_channel_unref(pChannel);
303 __pReverseSource = pGSource;
324 _IpcClient::OnReadMessage(GIOChannel* source, GIOCondition condition, gpointer data)
327 _IpcClient* pIpcClient = (_IpcClient*) data;
329 return pIpcClient->HandleReceivedMessage(source, condition);
333 _IpcClient::HandleReceivedMessage(GIOChannel* source, GIOCondition condition)
335 GError* pGError = null;
337 IPC::Message* pMessage = null;
339 if (condition & G_IO_HUP)
341 SysLog(NID_IO, "G_IO_HUP, the connection is closed.");
343 g_source_destroy(__pReverseSource);
344 g_source_unref(__pReverseSource);
345 __pReverseSource = null;
349 __pListener->OnIpcServerDisconnected(*this);
354 else if (condition & G_IO_IN)
357 const char* pStart = null;
358 const char* pEnd = null;
359 const char* pEndOfMessage = null;
364 status = g_io_channel_read_chars(source, (char*) __messageBuffer, __MAX_MESSAGE_BUFFER_SIZE, &readSize, &pGError);
365 if (status == G_IO_STATUS_EOF || status == G_IO_STATUS_ERROR)
367 if (status == G_IO_STATUS_EOF)
369 SysLog(NID_IO, "G_IO_STATUS_EOF, the connection is closed.");
373 SysLog(NID_IO, "G_IO_STATUS_ERROR, the connection is closed. ");
378 g_io_channel_shutdown(source, FALSE, &pGError);
380 g_source_destroy(__pReverseSource);
381 g_source_unref(__pReverseSource);
382 __pReverseSource = null;
386 __pListener->OnIpcServerDisconnected(*this);
397 if (__pending.empty())
399 pStart = __messageBuffer;
400 pEnd = pStart + readSize;
404 __pending.append(__messageBuffer, readSize);
405 pStart = __pending.data();
406 pEnd = pStart + __pending.size();
411 pEndOfMessage = IPC::Message::FindNext(pStart, pEnd);
412 if (pEndOfMessage == null)
414 __pending.assign(pStart, pEnd - pStart);
418 pMessage = new (std::nothrow) IPC::Message(pStart, pEndOfMessage - pStart);
419 SysTryReturn(NID_IO, pMessage != null, FALSE, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
423 __pListener->OnIpcResponseReceived(*this, *pMessage);
428 pStart = pEndOfMessage;
441 _IpcClient::AcquireFd(void)
443 result r = E_SUCCESS;
448 __pFdLock->Acquire();
449 if (__fds.size() == 0)
451 __pFdLock->Release();
452 r = MakeConnection(false);
453 SysTryReturn(NID_IO, !IsFailed(r), -1, r, "[%s] Failed to connect to the server.", GetErrorMessage(r));
461 __pFdLock->Release();
468 _IpcClient::ReleaseFd(int fd)
470 __pFdLock->Acquire();
474 __pFdLock->Release();
478 _IpcClient::SendAsync(IPC::Message* pMessage)
480 result r = E_SUCCESS;
487 pData = (char*) pMessage->data();
488 remain = pMessage->size();
491 SysTryReturnResult(NID_IO, fd != -1, E_SYSTEM, "Failed to get fd.");
495 written = write(fd, (char*) pData, remain);
502 SysLogException(NID_IO, E_RESOURCE_UNAVAILABLE, "[E_RESOURCE_UNAVAILABLE] The socket buffer is full.");
503 return E_RESOURCE_UNAVAILABLE;
506 SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Failed to send a request: %d, %s", errno, strerror(errno));
520 _IpcClient::SendSync(IPC::Message* pMessage)
522 result r = E_SUCCESS;
532 char* pEndOfMessage = null;
536 IPC::Message* pReply = null;
537 MessageReplyDeserializer* pReplyDeserializer = null;
538 IPC::SyncMessage* pSyncMessage = dynamic_cast <IPC::SyncMessage*>(pMessage);
539 SysTryReturnResult(NID_IO, pSyncMessage != null, E_INVALID_ARG, "pMessage is not a sync message.");
541 messageId = SyncMessage::GetMessageId(*pSyncMessage);
544 SysTryReturnResult(NID_IO, fd != -1, E_SYSTEM, "Failed to get fd.");
546 pData = (char*) pSyncMessage->data();
547 remain = pSyncMessage->size();
551 written = write(fd, (char*) pData, remain);
558 SysLogException(NID_IO, E_RESOURCE_UNAVAILABLE, "[E_RESOURCE_UNAVAILABLE] The socket buffer is full.");
559 return E_RESOURCE_UNAVAILABLE;
562 SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Failed to send a request: %d, %s", errno, strerror(errno));
574 pfd.events = POLLIN | POLLRDHUP;
581 ret = poll(&pfd, 1, -1);
589 SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Failed to poll (%d, %s).", errno, strerror(errno));
595 if (pfd.revents & POLLRDHUP)
597 SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] POLLRDHUP");
603 if (pfd.revents & POLLIN)
605 readSize = read(fd, buffer, 1024);
610 message.append(buffer, readSize);
613 pEndOfMessage = (char*) IPC::Message::FindNext(message.data(), message.data() + message.size());
616 pReply = new (std::nothrow) IPC::Message(message.data(), pEndOfMessage - message.data());
619 SysLogException(NID_IO, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
622 return E_OUT_OF_MEMORY;
629 pReplyDeserializer = pSyncMessage->GetReplyDeserializer();
630 pReplyDeserializer->SerializeOutputParameters(*pReply);
633 delete pReplyDeserializer;
641 _IpcClient::Send(IPC::Message* pMessage)
643 result r = E_SUCCESS;
645 SysAssertf(__pFdLock != null, "Not yet constructed. Construct() should be called before use.\n");
647 if (pMessage->is_sync())
649 r = SendSync(pMessage);
653 r = SendAsync(pMessage);
660 _IpcClient::SendRequest(IPC::Message* pMessage)
662 return Send(pMessage);
666 _IpcClient::SendRequest(const IPC::Message& message)
668 result r = E_SUCCESS;
670 SysAssertf(__pFdLock != null, "Not yet constructed. Construct() should be called before use.\n");
672 if (message.is_sync())
674 r = SendSync(const_cast<IPC::Message*>(&message));
678 r = SendAsync(const_cast<IPC::Message*>(&message));