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