9e98c9379babf67d471d52aa1db6a9cb7346ed9f
[platform/framework/native/appfw.git] / src / io / FIo_IpcClient.cpp
1 //
2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 //
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
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
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.
16 //
17
18 /**
19  * @file        FIo_IpcClient.cpp
20  * @brief       This is the implementation file for the _IpcClient class.
21  *
22  */
23
24 #include <stdio.h>
25 #include <errno.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <sys/un.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <poll.h>
33 #include <pthread.h>
34 #include <fcntl.h>
35
36 #include <iostream>
37 #include <queue>
38 #include <map>
39
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"
47
48 using namespace IPC;
49 using namespace std;
50 using namespace Tizen::App;
51 using namespace Tizen::App::Package;
52 using namespace Tizen::Base;
53 using namespace Tizen::Base::Runtime;
54
55 namespace Tizen { namespace Io
56 {
57
58 _IpcClient::_IpcClient(void)
59         : __pReverseSource(null)
60         , __fdCount(0)
61         , __pFdLock(null)
62         , __pListener(null)
63 {
64         __messageBuffer[0] = '\0';
65 }
66
67 _IpcClient::~_IpcClient(void)
68 {
69         int fd = 0;
70
71         if (__pReverseSource != null)
72         {
73                 g_source_destroy(__pReverseSource);
74                 g_source_unref(__pReverseSource);
75                 __pReverseSource = null;
76         }
77
78         while (__fds.size() > 0)
79         {
80                 fd = __fds.back();
81                 __fds.pop_back();
82
83                 close(fd);
84         }
85
86         delete __pFdLock;
87 }
88
89 result
90 _IpcClient::Construct(const String& name, const _IIpcClientEventListener* pListener)
91 {
92         SysAssertf(__pFdLock == null, "Already constructed. Calling Construct() twice or more on a same instance is not allowed for this class.");
93         result r = E_SUCCESS;
94         Mutex* pMutex = null;
95
96         __name = name;
97         __pListener = const_cast <_IIpcClientEventListener*>(pListener);
98
99         pMutex = new (std::nothrow) Mutex();
100         SysTryReturnResult(NID_IO, pMutex != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
101
102         r = pMutex->Create();
103         SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to create SourceLock.", GetErrorMessage(r));
104
105         __pFdLock = pMutex;
106
107         r = MakeConnection();
108         SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to connect to server.", GetErrorMessage(r));
109
110         if (__pListener)
111         {
112                 r = MakeConnection(true);
113                 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to connect to server.", GetErrorMessage(r));
114         }
115
116         return E_SUCCESS;
117
118 CATCH:
119         __name.Clear();
120         __pListener = null;
121         __pFdLock = null;
122
123         delete pMutex;
124
125         return r;
126 }
127
128 String
129 _IpcClient::GetName(void) const
130 {
131         return __name;
132 }
133
134 struct HelloMessage
135 {
136         int pid;
137         bool reverse;
138         char pkgId[256];
139         char appExecutableName[256];
140 };
141
142 result
143 _IpcClient::MakeConnection(bool forReverse)
144 {
145         result r = E_SUCCESS;
146
147         struct sockaddr_un server;
148         socklen_t serverLen = 0;
149         int client = -1;
150         int ret = 0;
151         HelloMessage helloMessage = {0, 0};
152         std::string socketName;
153         char* pSocketName = null;
154         size_t socketNameLength = 0;
155         int flags = 0;
156
157         helloMessage.pid = getpid();
158         if (forReverse)
159         {
160                 helloMessage.reverse = 1;
161         }
162         else
163         {
164                 helloMessage.reverse = 0;
165         }
166
167         pSocketName = _StringConverter::CopyToCharArrayN(__name);
168         SysTryReturnResult(NID_IO, pSocketName != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
169
170         socketName.append("/tmp/");
171         socketName.append(pSocketName);
172
173         delete[] pSocketName;
174
175         socketNameLength = socketName.size() + 1;
176         SysTryReturnResult(NID_IO, socketNameLength < 108, E_INVALID_ARG, "Server name is too long.");
177
178         if (__fdCount == 0)
179         {
180                 // Set an pkgId
181                 String pkgId = _AppInfo::GetPackageId();
182                 int length = (pkgId.GetLength() + 1) * sizeof(wchar_t);
183                 if (length > 255)
184                 {
185                         length = 255;
186                 }
187
188                 SysTryReturnResult(NID_IO, pkgId.GetLength() > 0, E_SYSTEM, "AppId dose not exist.");
189
190                 memcpy(helloMessage.pkgId, pkgId.GetPointer(), length);
191
192                 // Set an executableName
193                 String appExecutableName = _AppInfo::GetAppExecutableName();
194                 length = (appExecutableName.GetLength() + 1) * sizeof(wchar_t);
195                 if (length > 255)
196                 {
197                         length = 255;
198                 }
199
200                 if (appExecutableName.GetLength() != 0)
201                 {
202                         memcpy(helloMessage.appExecutableName, appExecutableName.GetPointer(), length);
203                 }
204         }
205
206         client = socket(AF_UNIX, SOCK_STREAM, 0);
207         SysTryCatch(NID_IO, client != -1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to create a socket : %s.", strerror(errno));
208
209         flags = fcntl(client, F_GETFL, 0);
210         ret = fcntl(client, F_SETFL, flags | O_NONBLOCK);
211         SysTryCatch(NID_IO, ret >= 0 , r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to set file status flags (%d, %s).",
212                                            errno, strerror(errno));
213
214         bzero(&server, sizeof(server));
215         server.sun_family = AF_UNIX;
216         strncpy(server.sun_path, socketName.c_str(), socketNameLength);
217         serverLen = sizeof(server);
218
219         ret = connect(client, (struct sockaddr*) &server, serverLen);
220         if (ret != 0)
221         {
222                 SysTryCatch(NID_IO, errno == EINPROGRESS, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to connect to server(%s) : %s",
223                                    socketName.c_str(), strerror(errno));
224
225                 fd_set rset;
226                 fd_set wset;
227                 struct timeval timeout;
228                 int length = 0;
229                 int error = 0;
230                 socklen_t socketLength = 0;
231
232                 FD_ZERO(&rset);
233                 FD_SET(client, &rset);
234                 wset = rset;
235                 timeout.tv_sec = 10;
236                 timeout.tv_usec = 0;
237
238                 while (true)
239                 {
240                         ret = select(client+1, &rset, &wset, NULL, &timeout);
241                         if (ret < 0)
242                         {
243                                 SysTryCatch(NID_IO, errno == EINTR , r = E_SYSTEM, E_SYSTEM, "[E_TIMEOUT] Failed to connect due to system error.");
244
245                                 continue;
246                         }
247                         else if (ret == 0)
248                         {
249                                 r = E_TIMEOUT;
250                                 SysLogException(NID_IO, E_TIMEOUT, "[E_TIMEOUT] Failed to connect due to timeout.");
251                                 goto CATCH;
252                         }
253                         else
254                         {
255                                 break;
256                         }
257                 }
258
259                 if (FD_ISSET(client, &rset) || FD_ISSET(client, &wset))
260                 {
261                         length = sizeof(error);
262                         ret = getsockopt(client, SOL_SOCKET, SO_ERROR, &error, &socketLength);
263                         SysTryCatch(NID_IO, ret >= 0 , r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to connect to server(%s) : %s",
264                                            socketName.c_str(), strerror(errno));
265                 }
266                 else
267                 {
268                         r = E_SYSTEM;
269                         SysLogException(NID_IO, E_SYSTEM, "[E_TIMEOUT] Failed to connect due to system error.");
270                         goto CATCH;
271                 }
272         }
273
274         ret = fcntl(client, F_SETFL, flags);
275         SysTryCatch(NID_IO, ret >= 0 , r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to set file status flags (%d, %s).",
276                                            errno, strerror(errno));
277
278         write(client, &helloMessage, sizeof(helloMessage));
279
280         if (forReverse)
281         {
282                 GError* pGError = null;
283                 GSource* pGSource = null;
284                 ;
285                 GIOChannel* pChannel = g_io_channel_unix_new(client);
286                 GMainContext* pGMainContext = g_main_context_default();
287
288                 g_io_channel_set_encoding(pChannel, null, &pGError);
289                 g_io_channel_set_flags(pChannel, G_IO_FLAG_NONBLOCK, &pGError);
290                 g_io_channel_set_close_on_unref(pChannel, TRUE);
291
292                 pGSource = g_io_create_watch(pChannel, (GIOCondition) (G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP));
293                 g_source_set_callback(pGSource, (GSourceFunc) OnReadMessage, this, null);
294                 g_source_attach(pGSource, pGMainContext);
295
296                 g_io_channel_unref(pChannel);
297                 __pReverseSource = pGSource;
298         }
299         else
300         {
301                 ++__fdCount;
302
303                 ReleaseFd(client);
304         }
305
306         return r;
307
308 CATCH:
309         if (client != -1)
310         {
311                 close(client);
312         }
313
314         return r;
315 }
316
317 gboolean
318 _IpcClient::OnReadMessage(GIOChannel* source, GIOCondition condition, gpointer data)
319 {
320
321         _IpcClient* pIpcClient = (_IpcClient*) data;
322
323         return pIpcClient->HandleReceivedMessage(source, condition);
324 }
325
326 gboolean
327 _IpcClient::HandleReceivedMessage(GIOChannel* source, GIOCondition condition)
328 {
329         GError* pGError = null;
330         GIOStatus status;
331         IPC::Message* pMessage = null;
332
333         if (condition & G_IO_HUP)
334         {
335                 SysLog(NID_IO, "G_IO_HUP, the connection is closed.");
336
337                 g_source_destroy(__pReverseSource);
338                 g_source_unref(__pReverseSource);
339                 __pReverseSource = null;
340
341                 if (__pListener)
342                 {
343                         __pListener->OnIpcServerDisconnected(*this);
344                 }
345
346                 return FALSE;
347         }
348         else if (condition & G_IO_IN)
349         {
350                 gsize readSize = 0;
351                 const char* pStart = null;
352                 const char* pEnd = null;
353                 const char* pEndOfMessage = null;
354
355                 while (true)
356                 {
357                         pGError = null;
358                         status = g_io_channel_read_chars(source, (char*) __messageBuffer, __MAX_MESSAGE_BUFFER_SIZE, &readSize, &pGError);
359                         if (status == G_IO_STATUS_EOF || status == G_IO_STATUS_ERROR)
360                         {
361                                 if (status == G_IO_STATUS_EOF)
362                                 {
363                                         SysLog(NID_IO, "G_IO_STATUS_EOF, the connection is closed.");
364                                 }
365                                 else
366                                 {
367                                         SysLog(NID_IO, "G_IO_STATUS_ERROR, the connection is closed. ");
368                                 }
369
370                                 pGError = null;
371
372                                 g_io_channel_shutdown(source, FALSE, &pGError);
373
374                                 g_source_destroy(__pReverseSource);
375                                 g_source_unref(__pReverseSource);
376                                 __pReverseSource = null;
377
378                                 if (__pListener)
379                                 {
380                                         __pListener->OnIpcServerDisconnected(*this);
381                                 }
382
383                                 return FALSE;
384                         }
385
386                         if (readSize == 0)
387                         {
388                                 break;
389                         }
390
391                         if (__pending.empty())
392                         {
393                                 pStart = __messageBuffer;
394                                 pEnd = pStart + readSize;
395                         }
396                         else
397                         {
398                                 __pending.append(__messageBuffer, readSize);
399                                 pStart = __pending.data();
400                                 pEnd = pStart + __pending.size();
401                         }
402
403                         while (true)
404                         {
405                                 pEndOfMessage = IPC::Message::FindNext(pStart, pEnd);
406                                 if (pEndOfMessage == null)
407                                 {
408                                         __pending.assign(pStart, pEnd - pStart);
409                                         break;
410                                 }
411
412                                 pMessage = new (std::nothrow) IPC::Message(pStart, pEndOfMessage - pStart);
413                                 SysTryReturn(NID_IO, pMessage != null, FALSE, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
414
415                                 if (__pListener)
416                                 {
417                                         __pListener->OnIpcResponseReceived(*this, *pMessage);
418                                 }
419
420                                 delete pMessage;
421
422                                 pStart = pEndOfMessage;
423                         }
424                 }
425         }
426         else
427         {
428                 // empty statement.
429         }
430
431         return TRUE;
432 }
433
434 int
435 _IpcClient::AcquireFd(void)
436 {
437         result r = E_SUCCESS;
438         int fd = -1;
439
440         while (fd == -1)
441         {
442                 __pFdLock->Acquire();
443                 if (__fds.size() == 0)
444                 {
445                         __pFdLock->Release();
446                         r = MakeConnection(false);
447                         SysTryReturn(NID_IO, !IsFailed(r), -1, r, "[%s] Failed to connect to the server.", GetErrorMessage(r));
448
449                         continue;
450                 }
451
452                 fd = __fds.back();
453                 __fds.pop_back();
454
455                 __pFdLock->Release();
456         }
457
458         return fd;
459 }
460
461 void
462 _IpcClient::ReleaseFd(int fd)
463 {
464         __pFdLock->Acquire();
465
466         __fds.push_back(fd);
467
468         __pFdLock->Release();
469 }
470
471 result
472 _IpcClient::SendAsync(IPC::Message* pMessage)
473 {
474         result r = E_SUCCESS;
475
476         int fd = -1;
477         char* pData = null;
478         int remain = 0;
479         int written = 0;
480
481         pData = (char*) pMessage->data();
482         remain = pMessage->size();
483
484         fd = AcquireFd();
485         SysTryReturnResult(NID_IO, fd != -1, E_SYSTEM, "Failed to get fd.");
486
487         while (remain > 0)
488         {
489                 written = write(fd, (char*) pData, remain);
490                 remain -= written;
491                 pData += written;
492         }
493
494         ReleaseFd(fd);
495
496         return r;
497 }
498
499 result
500 _IpcClient::SendSync(IPC::Message* pMessage)
501 {
502         result r = E_SUCCESS;
503
504         int messageId = 0;
505         int fd = -1;
506
507         char* pData = null;
508         int remain = 0;
509         int written = 0;
510         int readSize = 0;
511         char buffer[1024];
512         char* pEndOfMessage = null;
513
514         std::string message;
515
516         struct pollfd pfd;
517
518         IPC::Message* pReply = null;
519         MessageReplyDeserializer* pReplyDeserializer = null;
520         IPC::SyncMessage* pSyncMessage = dynamic_cast <IPC::SyncMessage*>(pMessage);
521         SysTryReturnResult(NID_IO, pSyncMessage != null, E_INVALID_ARG, "pMessage is not a sync message.");
522
523         messageId = SyncMessage::GetMessageId(*pSyncMessage);
524
525         fd = AcquireFd();
526         SysTryReturnResult(NID_IO, fd != -1, E_SYSTEM, "Failed to get fd.");
527
528         pData = (char*) pSyncMessage->data();
529         remain = pSyncMessage->size();
530
531         while (remain > 0)
532         {
533                 written = write(fd, (char*) pData, remain);
534                 remain -= written;
535                 pData += written;
536         }
537
538         // Wait reply
539         pfd.fd = fd;
540         pfd.events = POLLIN | POLLRDHUP;
541         pfd.revents = 0;
542
543         while (true)
544         {
545                 poll(&pfd, 1, -1);
546
547                 if (pfd.revents & POLLRDHUP)
548                 {
549                         return E_SYSTEM;
550                 }
551
552                 if (pfd.revents & POLLIN)
553                 {
554                         readSize = read(fd, buffer, 1024);
555                 }
556
557                 message.append(buffer, readSize);
558
559                 pEndOfMessage = (char*) IPC::Message::FindNext(message.data(), message.data() + message.size());
560                 if (pEndOfMessage)
561                 {
562                         pReply = new (std::nothrow) IPC::Message(message.data(), pEndOfMessage - message.data());
563                         SysTryReturnResult(NID_IO, pReply != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
564                         break;
565                 }
566         }
567
568         pReplyDeserializer = pSyncMessage->GetReplyDeserializer();
569         pReplyDeserializer->SerializeOutputParameters(*pReply);
570
571         delete pReply;
572         delete pReplyDeserializer;
573
574         ReleaseFd(fd);
575
576         return r;
577 }
578
579 result
580 _IpcClient::Send(IPC::Message* pMessage)
581 {
582         result r = E_SUCCESS;
583
584         SysAssertf(__pFdLock != null, "Not yet constructed. Construct() should be called before use.\n");
585
586         if (pMessage->is_sync())
587         {
588                 r = SendSync(pMessage);
589         }
590         else
591         {
592                 r = SendAsync(pMessage);
593         }
594
595         return r;
596 }
597
598 result
599 _IpcClient::SendRequest(IPC::Message* pMessage)
600 {
601         return Send(pMessage);
602 }
603
604 result
605 _IpcClient::SendRequest(const IPC::Message& message)
606 {
607         result r = E_SUCCESS;
608
609         SysAssertf(__pFdLock != null, "Not yet constructed. Construct() should be called before use.\n");
610
611         if (message.is_sync())
612         {
613                 r = SendSync(const_cast<IPC::Message*>(&message));
614         }
615         else
616         {
617                 r = SendAsync(const_cast<IPC::Message*>(&message));
618         }
619
620         return r;
621 }
622
623 } } //Tizen::Io