780bb7f714bb5bc87c4c654f32ea51a6254a924e
[platform/framework/native/appfw.git] / src / io / FIo_IpcClient.cpp
1 //
2 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
3 //
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
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
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.
15 //
16
17 /**
18  * @file        FIo_IpcClient.cpp
19  * @brief       This is the implementation file for the _IpcClient class.
20  *
21  */
22
23 #include <stdio.h>
24 #include <errno.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/un.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <poll.h>
32 #include <pthread.h>
33 #include <fcntl.h>
34
35 #include <iostream>
36 #include <queue>
37 #include <map>
38
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"
46
47 using namespace IPC;
48 using namespace std;
49 using namespace Tizen::App;
50 using namespace Tizen::App::Package;
51 using namespace Tizen::Base;
52 using namespace Tizen::Base::Runtime;
53
54 namespace Tizen { namespace Io
55 {
56
57 _IpcClient::_IpcClient(void)
58         : __pReverseSource(null)
59         , __fdCount(0)
60         , __timeout(-1)
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 appId[256];
139 };
140
141 result
142 _IpcClient::MakeConnection(bool forReverse)
143 {
144         result r = E_SUCCESS;
145
146         struct sockaddr_un server;
147         socklen_t serverLen = 0;
148         int client = -1;
149         int ret = 0;
150         int retry = 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 appId
181                 String appId = _AppInfo::GetApplicationId();
182                 int length = (appId.GetLength() + 1) * sizeof(wchar_t);
183                 if (length > 255)
184                 {
185                         length = 255;
186                 }
187
188                 SysTryReturnResult(NID_IO, appId.GetLength() > 0, E_SYSTEM, "AppId dose not exist.");
189
190                 memcpy(helloMessage.appId, appId.GetPointer(), length);
191         }
192
193         client = socket(AF_UNIX, SOCK_STREAM, 0);
194         SysTryCatch(NID_IO, client != -1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to create a socket : %s.", strerror(errno));
195
196         flags = fcntl(client, F_GETFL, 0);
197         ret = fcntl(client, F_SETFL, flags | O_NONBLOCK);
198         SysTryCatch(NID_IO, ret >= 0 , r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to set file status flags (%d, %s).",
199                                            errno, strerror(errno));
200
201         bzero(&server, sizeof(server));
202         server.sun_family = AF_UNIX;
203         strncpy(server.sun_path, socketName.c_str(), socketNameLength);
204         serverLen = sizeof(server);
205
206         // Retry if the server is not ready
207         retry = 5;
208         while (retry > 0)
209         {
210                 ret = connect(client, (struct sockaddr*) &server, serverLen);
211                 if (ret < 0 && errno == ENOENT)
212                 {
213                         SysLog(NID_IO, "The server is not ready. %d", retry);
214
215                         usleep(1000 * 1000);
216
217                         --retry;
218                 }
219                 else
220                 {
221                         break;
222                 }
223         }
224
225         if (ret < 0)
226         {
227                 SysTryCatch(NID_IO, errno == EINPROGRESS, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to connect to server(%s) : %s",
228                                    socketName.c_str(), strerror(errno));
229
230                 fd_set rset;
231                 fd_set wset;
232                 struct timeval timeout;
233                 int length = 0;
234                 int error = 0;
235                 socklen_t socketLength = 0;
236
237                 FD_ZERO(&rset);
238                 FD_SET(client, &rset);
239                 wset = rset;
240                 timeout.tv_sec = 10;
241                 timeout.tv_usec = 0;
242
243                 while (true)
244                 {
245                         ret = select(client+1, &rset, &wset, NULL, &timeout);
246                         if (ret < 0)
247                         {
248                                 SysTryCatch(NID_IO, errno == EINTR , r = E_SYSTEM, E_SYSTEM, "[E_TIMEOUT] Failed to connect due to system error.");
249
250                                 continue;
251                         }
252                         else if (ret == 0)
253                         {
254                                 r = E_TIMEOUT;
255                                 SysLogException(NID_IO, E_TIMEOUT, "[E_TIMEOUT] Failed to connect due to timeout.");
256                                 goto CATCH;
257                         }
258                         else
259                         {
260                                 break;
261                         }
262                 }
263
264                 if (FD_ISSET(client, &rset) || FD_ISSET(client, &wset))
265                 {
266                         length = sizeof(error);
267                         ret = getsockopt(client, SOL_SOCKET, SO_ERROR, &error, &socketLength);
268                         SysTryCatch(NID_IO, ret >= 0 , r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to connect to server(%s) : %s",
269                                            socketName.c_str(), strerror(errno));
270                 }
271                 else
272                 {
273                         r = E_SYSTEM;
274                         SysLogException(NID_IO, E_SYSTEM, "[E_TIMEOUT] Failed to connect due to system error.");
275                         goto CATCH;
276                 }
277         }
278
279         ret = fcntl(client, F_SETFL, flags);
280         SysTryCatch(NID_IO, ret >= 0 , r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to set file status flags (%d, %s).",
281                                            errno, strerror(errno));
282
283         write(client, &helloMessage, sizeof(helloMessage));
284
285         if (forReverse)
286         {
287                 GError* pGError = null;
288                 GSource* pGSource = null;
289                 ;
290                 GIOChannel* pChannel = g_io_channel_unix_new(client);
291                 GMainContext* pGMainContext = g_main_context_default();
292
293                 g_io_channel_set_encoding(pChannel, null, &pGError);
294                 g_io_channel_set_flags(pChannel, G_IO_FLAG_NONBLOCK, &pGError);
295                 g_io_channel_set_close_on_unref(pChannel, TRUE);
296
297                 pGSource = g_io_create_watch(pChannel, (GIOCondition) (G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP));
298                 g_source_set_callback(pGSource, (GSourceFunc) OnReadMessage, this, null);
299                 g_source_attach(pGSource, pGMainContext);
300
301                 g_io_channel_unref(pChannel);
302                 __pReverseSource = pGSource;
303         }
304         else
305         {
306                 ++__fdCount;
307
308                 ReleaseFd(client);
309         }
310
311         return r;
312
313 CATCH:
314         if (client != -1)
315         {
316                 close(client);
317         }
318
319         return r;
320 }
321
322 gboolean
323 _IpcClient::OnReadMessage(GIOChannel* source, GIOCondition condition, gpointer data)
324 {
325
326         _IpcClient* pIpcClient = (_IpcClient*) data;
327
328         return pIpcClient->HandleReceivedMessage(source, condition);
329 }
330
331 gboolean
332 _IpcClient::HandleReceivedMessage(GIOChannel* source, GIOCondition condition)
333 {
334         GError* pGError = null;
335         GIOStatus status;
336         IPC::Message* pMessage = null;
337
338         if (condition & G_IO_HUP)
339         {
340                 SysLog(NID_IO, "G_IO_HUP, the connection is closed.");
341
342                 g_source_destroy(__pReverseSource);
343                 g_source_unref(__pReverseSource);
344                 __pReverseSource = null;
345
346                 if (__pListener)
347                 {
348                         __pListener->OnIpcServerDisconnected(*this);
349                 }
350
351                 return FALSE;
352         }
353         else if (condition & G_IO_IN)
354         {
355                 gsize readSize = 0;
356                 const char* pStart = null;
357                 const char* pEnd = null;
358                 const char* pEndOfMessage = null;
359
360                 while (true)
361                 {
362                         pGError = null;
363                         status = g_io_channel_read_chars(source, (char*) __messageBuffer, __MAX_MESSAGE_BUFFER_SIZE, &readSize, &pGError);
364                         if (status == G_IO_STATUS_EOF || status == G_IO_STATUS_ERROR)
365                         {
366                                 if (status == G_IO_STATUS_EOF)
367                                 {
368                                         SysLog(NID_IO, "G_IO_STATUS_EOF, the connection is closed.");
369                                 }
370                                 else
371                                 {
372                                         SysLog(NID_IO, "G_IO_STATUS_ERROR, the connection is closed. ");
373                                 }
374
375                                 pGError = null;
376
377                                 g_io_channel_shutdown(source, FALSE, &pGError);
378
379                                 g_source_destroy(__pReverseSource);
380                                 g_source_unref(__pReverseSource);
381                                 __pReverseSource = null;
382
383                                 if (__pListener)
384                                 {
385                                         __pListener->OnIpcServerDisconnected(*this);
386                                 }
387
388                                 return FALSE;
389                         }
390
391                         if (readSize == 0)
392                         {
393                                 break;
394                         }
395
396                         if (__pending.empty())
397                         {
398                                 pStart = __messageBuffer;
399                                 pEnd = pStart + readSize;
400                         }
401                         else
402                         {
403                                 __pending.append(__messageBuffer, readSize);
404                                 pStart = __pending.data();
405                                 pEnd = pStart + __pending.size();
406                         }
407
408                         while (true)
409                         {
410                                 pEndOfMessage = IPC::Message::FindNext(pStart, pEnd);
411                                 if (pEndOfMessage == null)
412                                 {
413                                         __pending.assign(pStart, pEnd - pStart);
414                                         break;
415                                 }
416
417                                 pMessage = new (std::nothrow) IPC::Message(pStart, pEndOfMessage - pStart);
418                                 SysTryReturn(NID_IO, pMessage != null, FALSE, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
419
420                                 if (__pListener)
421                                 {
422                                         __pListener->OnIpcResponseReceived(*this, *pMessage);
423                                 }
424
425                                 delete pMessage;
426
427                                 pStart = pEndOfMessage;
428                         }
429                 }
430         }
431         else
432         {
433                 // empty statement.
434         }
435
436         return TRUE;
437 }
438
439 int
440 _IpcClient::AcquireFd(void)
441 {
442         result r = E_SUCCESS;
443         int fd = -1;
444
445         while (fd == -1)
446         {
447                 __pFdLock->Acquire();
448                 if (__fds.size() == 0)
449                 {
450                         __pFdLock->Release();
451                         r = MakeConnection(false);
452                         SysTryReturn(NID_IO, !IsFailed(r), -1, r, "[%s] Failed to connect to the server.", GetErrorMessage(r));
453
454                         continue;
455                 }
456
457                 fd = __fds.back();
458                 __fds.pop_back();
459
460                 __pFdLock->Release();
461         }
462
463         return fd;
464 }
465
466 void
467 _IpcClient::ReleaseFd(int fd)
468 {
469         __pFdLock->Acquire();
470
471         __fds.push_back(fd);
472
473         __pFdLock->Release();
474 }
475
476 result
477 _IpcClient::SendAsync(IPC::Message* pMessage)
478 {
479         result r = E_SUCCESS;
480
481         int fd = -1;
482         char* pData = null;
483         int remain = 0;
484         int written = 0;
485
486         pData = (char*) pMessage->data();
487         remain = pMessage->size();
488
489         fd = AcquireFd();
490         SysTryReturnResult(NID_IO, fd != -1, E_SYSTEM, "Failed to get fd.");
491
492         while (remain > 0)
493         {
494                 written = write(fd, (char*) pData, remain);
495                 if (written < 0)
496                 {
497                         SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Failed to send a request: %d, %s", errno, strerror(errno));
498
499                         ReleaseFd(fd);
500                         return E_SYSTEM;
501                 }
502
503                 remain -= written;
504                 pData += written;
505         }
506
507         ReleaseFd(fd);
508
509         return r;
510 }
511
512 result
513 _IpcClient::SendSync(IPC::Message* pMessage)
514 {
515         result r = E_SUCCESS;
516
517         int messageId = 0;
518         int fd = -1;
519
520         char* pData = null;
521         int remain = 0;
522         int written = 0;
523         int readSize = 0;
524         char buffer[1024];
525         char* pEndOfMessage = null;
526
527         std::string message;
528
529         IPC::Message* pReply = null;
530         MessageReplyDeserializer* pReplyDeserializer = null;
531         IPC::SyncMessage* pSyncMessage = dynamic_cast <IPC::SyncMessage*>(pMessage);
532         SysTryReturnResult(NID_IO, pSyncMessage != null, E_INVALID_ARG, "pMessage is not a sync message.");
533
534         messageId = SyncMessage::GetMessageId(*pSyncMessage);
535
536         fd = AcquireFd();
537         SysTryReturnResult(NID_IO, fd != -1, E_SYSTEM, "Failed to get fd.");
538
539         pData = (char*) pSyncMessage->data();
540         remain = pSyncMessage->size();
541
542         while (remain > 0)
543         {
544                 written = write(fd, (char*) pData, remain);
545                 if (written < 0)
546                 {
547                         SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Failed to send a request: %d, %s", errno, strerror(errno));
548
549                         ReleaseFd(fd);
550                         return E_SYSTEM;
551                 }
552
553                 remain -= written;
554                 pData += written;
555         }
556
557         // Wait reply
558         struct pollfd pfd;
559
560         pfd.fd = fd;
561         pfd.events = POLLIN | POLLRDHUP;
562         pfd.revents = 0;
563
564         int ret = 0;
565
566         while (true)
567         {
568                 ret = poll(&pfd, 1, __timeout);
569                 if (ret < 0)
570                 {
571                         if (errno == EINTR)
572                         {
573                                 continue;
574                         }
575
576                         SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Failed to poll (%d, %s).", errno, strerror(errno));
577
578                         ReleaseFd(fd);
579                         return E_SYSTEM;
580                 }
581                 else if (ret == 0)
582                 {
583                         SysLogException(NID_IO, E_TIMEOUT, "[E_TIMEOUT] Timeout.");
584
585                         ReleaseFd(fd);
586                         return E_TIMEOUT;
587                 }
588
589                 if (pfd.revents & POLLRDHUP)
590                 {
591                         SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] POLLRDHUP");
592
593                         ReleaseFd(fd);
594                         return E_SYSTEM;
595                 }
596
597                 if (pfd.revents & POLLIN)
598                 {
599                         readSize = read(fd, buffer, 1024);
600                 }
601
602                 if (readSize > 0)
603                 {
604                         message.append(buffer, readSize);
605                 }
606
607                 pEndOfMessage = (char*) IPC::Message::FindNext(message.data(), message.data() + message.size());
608                 if (pEndOfMessage)
609                 {
610                         pReply = new (std::nothrow) IPC::Message(message.data(), pEndOfMessage - message.data());
611                         if (pReply == null)
612                         {
613                                 SysLogException(NID_IO, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
614
615                                 ReleaseFd(fd);
616                                 return E_OUT_OF_MEMORY;
617                         }
618
619                         break;
620                 }
621         }
622
623         pReplyDeserializer = pSyncMessage->GetReplyDeserializer();
624         pReplyDeserializer->SerializeOutputParameters(*pReply);
625
626         delete pReply;
627         delete pReplyDeserializer;
628
629         ReleaseFd(fd);
630
631         return r;
632 }
633
634 result
635 _IpcClient::Send(IPC::Message* pMessage)
636 {
637         result r = E_SUCCESS;
638
639         SysAssertf(__pFdLock != null, "Not yet constructed. Construct() should be called before use.\n");
640
641         if (pMessage->is_sync())
642         {
643                 r = SendSync(pMessage);
644         }
645         else
646         {
647                 r = SendAsync(pMessage);
648         }
649
650         return r;
651 }
652
653 result
654 _IpcClient::SendRequest(IPC::Message* pMessage)
655 {
656         return Send(pMessage);
657 }
658
659 result
660 _IpcClient::SendRequest(const IPC::Message& message)
661 {
662         result r = E_SUCCESS;
663
664         SysAssertf(__pFdLock != null, "Not yet constructed. Construct() should be called before use.\n");
665
666         if (message.is_sync())
667         {
668                 r = SendSync(const_cast<IPC::Message*>(&message));
669         }
670         else
671         {
672                 r = SendAsync(const_cast<IPC::Message*>(&message));
673         }
674
675         return r;
676 }
677
678 void
679 _IpcClient::SetTimeout(int timeout)
680 {
681         __timeout = timeout;
682 }
683
684 int
685 _IpcClient::GetTimeout(void) const
686 {
687         return __timeout;
688 }
689
690 } } //Tizen::Io