6e4417eb064dfed337ffc0c94048cc1e3bcf35c0
[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         int retry = 0;
150         HelloMessage helloMessage = {0, 0};
151         std::string socketName;
152         char* pSocketName = null;
153         size_t socketNameLength = 0;
154         int flags = 0;
155
156         helloMessage.pid = getpid();
157         if (forReverse)
158         {
159                 helloMessage.reverse = 1;
160         }
161         else
162         {
163                 helloMessage.reverse = 0;
164         }
165
166         pSocketName = _StringConverter::CopyToCharArrayN(__name);
167         SysTryReturnResult(NID_IO, pSocketName != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
168
169         socketName.append("/tmp/");
170         socketName.append(pSocketName);
171
172         delete[] pSocketName;
173
174         socketNameLength = socketName.size() + 1;
175         SysTryReturnResult(NID_IO, socketNameLength < 108, E_INVALID_ARG, "Server name is too long.");
176
177         if (__fdCount == 0)
178         {
179                 // Set an appId
180                 String appId = _AppInfo::GetApplicationId();
181                 int length = (appId.GetLength() + 1) * sizeof(wchar_t);
182                 if (length > 255)
183                 {
184                         length = 255;
185                 }
186
187                 SysTryReturnResult(NID_IO, appId.GetLength() > 0, E_SYSTEM, "AppId dose not exist.");
188
189                 memcpy(helloMessage.appId, appId.GetPointer(), length);
190         }
191
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));
194
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));
199
200         bzero(&server, sizeof(server));
201         server.sun_family = AF_UNIX;
202         strncpy(server.sun_path, socketName.c_str(), socketNameLength);
203         serverLen = sizeof(server);
204
205         // Retry if the server is not ready
206         retry = 5;
207         while (retry > 0)
208         {
209                 ret = connect(client, (struct sockaddr*) &server, serverLen);
210                 if (ret < 0 && errno == ENOENT)
211                 {
212                         SysLog(NID_IO, "The server is not ready. %d", retry);
213
214                         usleep(1000 * 1000);
215
216                         --retry;
217                 }
218                 else
219                 {
220                         break;
221                 }
222         }
223
224         if (ret < 0)
225         {
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));
228
229                 fd_set rset;
230                 fd_set wset;
231                 struct timeval timeout;
232                 int length = 0;
233                 int error = 0;
234                 socklen_t socketLength = 0;
235
236                 FD_ZERO(&rset);
237                 FD_SET(client, &rset);
238                 wset = rset;
239                 timeout.tv_sec = 10;
240                 timeout.tv_usec = 0;
241
242                 while (true)
243                 {
244                         ret = select(client+1, &rset, &wset, NULL, &timeout);
245                         if (ret < 0)
246                         {
247                                 SysTryCatch(NID_IO, errno == EINTR , r = E_SYSTEM, E_SYSTEM, "[E_TIMEOUT] Failed to connect due to system error.");
248
249                                 continue;
250                         }
251                         else if (ret == 0)
252                         {
253                                 r = E_TIMEOUT;
254                                 SysLogException(NID_IO, E_TIMEOUT, "[E_TIMEOUT] Failed to connect due to timeout.");
255                                 goto CATCH;
256                         }
257                         else
258                         {
259                                 break;
260                         }
261                 }
262
263                 if (FD_ISSET(client, &rset) || FD_ISSET(client, &wset))
264                 {
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));
269                 }
270                 else
271                 {
272                         r = E_SYSTEM;
273                         SysLogException(NID_IO, E_SYSTEM, "[E_TIMEOUT] Failed to connect due to system error.");
274                         goto CATCH;
275                 }
276         }
277
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));
281
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));
285
286         if (forReverse)
287         {
288                 GError* pGError = null;
289                 GSource* pGSource = null;
290                 ;
291                 GIOChannel* pChannel = g_io_channel_unix_new(client);
292                 GMainContext* pGMainContext = g_main_context_default();
293
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);
297
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);
301
302                 g_io_channel_unref(pChannel);
303                 __pReverseSource = pGSource;
304         }
305         else
306         {
307                 ++__fdCount;
308
309                 ReleaseFd(client);
310         }
311
312         return r;
313
314 CATCH:
315         if (client != -1)
316         {
317                 close(client);
318         }
319
320         return r;
321 }
322
323 gboolean
324 _IpcClient::OnReadMessage(GIOChannel* source, GIOCondition condition, gpointer data)
325 {
326
327         _IpcClient* pIpcClient = (_IpcClient*) data;
328
329         return pIpcClient->HandleReceivedMessage(source, condition);
330 }
331
332 gboolean
333 _IpcClient::HandleReceivedMessage(GIOChannel* source, GIOCondition condition)
334 {
335         GError* pGError = null;
336         GIOStatus status;
337         IPC::Message* pMessage = null;
338
339         if (condition & G_IO_HUP)
340         {
341                 SysLog(NID_IO, "G_IO_HUP, the connection is closed.");
342
343                 g_source_destroy(__pReverseSource);
344                 g_source_unref(__pReverseSource);
345                 __pReverseSource = null;
346
347                 if (__pListener)
348                 {
349                         __pListener->OnIpcServerDisconnected(*this);
350                 }
351
352                 return FALSE;
353         }
354         else if (condition & G_IO_IN)
355         {
356                 gsize readSize = 0;
357                 const char* pStart = null;
358                 const char* pEnd = null;
359                 const char* pEndOfMessage = null;
360
361                 while (true)
362                 {
363                         pGError = 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)
366                         {
367                                 if (status == G_IO_STATUS_EOF)
368                                 {
369                                         SysLog(NID_IO, "G_IO_STATUS_EOF, the connection is closed.");
370                                 }
371                                 else
372                                 {
373                                         SysLog(NID_IO, "G_IO_STATUS_ERROR, the connection is closed. ");
374                                 }
375
376                                 pGError = null;
377
378                                 g_io_channel_shutdown(source, FALSE, &pGError);
379
380                                 g_source_destroy(__pReverseSource);
381                                 g_source_unref(__pReverseSource);
382                                 __pReverseSource = null;
383
384                                 if (__pListener)
385                                 {
386                                         __pListener->OnIpcServerDisconnected(*this);
387                                 }
388
389                                 return FALSE;
390                         }
391
392                         if (readSize == 0)
393                         {
394                                 break;
395                         }
396
397                         if (__pending.empty())
398                         {
399                                 pStart = __messageBuffer;
400                                 pEnd = pStart + readSize;
401                         }
402                         else
403                         {
404                                 __pending.append(__messageBuffer, readSize);
405                                 pStart = __pending.data();
406                                 pEnd = pStart + __pending.size();
407                         }
408
409                         while (true)
410                         {
411                                 pEndOfMessage = IPC::Message::FindNext(pStart, pEnd);
412                                 if (pEndOfMessage == null)
413                                 {
414                                         __pending.assign(pStart, pEnd - pStart);
415                                         break;
416                                 }
417
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.");
420
421                                 if (__pListener)
422                                 {
423                                         __pListener->OnIpcResponseReceived(*this, *pMessage);
424                                 }
425
426                                 delete pMessage;
427
428                                 pStart = pEndOfMessage;
429                         }
430                 }
431         }
432         else
433         {
434                 // empty statement.
435         }
436
437         return TRUE;
438 }
439
440 int
441 _IpcClient::AcquireFd(void)
442 {
443         result r = E_SUCCESS;
444         int fd = -1;
445
446         while (fd == -1)
447         {
448                 __pFdLock->Acquire();
449                 if (__fds.size() == 0)
450                 {
451                         __pFdLock->Release();
452                         r = MakeConnection(false);
453                         SysTryReturn(NID_IO, !IsFailed(r), -1, r, "[%s] Failed to connect to the server.", GetErrorMessage(r));
454
455                         continue;
456                 }
457
458                 fd = __fds.back();
459                 __fds.pop_back();
460
461                 __pFdLock->Release();
462         }
463
464         return fd;
465 }
466
467 void
468 _IpcClient::ReleaseFd(int fd)
469 {
470         __pFdLock->Acquire();
471
472         __fds.push_back(fd);
473
474         __pFdLock->Release();
475 }
476
477 result
478 _IpcClient::SendAsync(IPC::Message* pMessage)
479 {
480         result r = E_SUCCESS;
481
482         int fd = -1;
483         char* pData = null;
484         int remain = 0;
485         int written = 0;
486
487         pData = (char*) pMessage->data();
488         remain = pMessage->size();
489
490         fd = AcquireFd();
491         SysTryReturnResult(NID_IO, fd != -1, E_SYSTEM, "Failed to get fd.");
492
493         while (remain > 0)
494         {
495                 written = write(fd, (char*) pData, remain);
496                 if (written < 0)
497                 {
498                         ReleaseFd(fd);
499
500                         if (errno == EAGAIN)
501                         {
502                                 SysLogException(NID_IO, E_RESOURCE_UNAVAILABLE, "[E_RESOURCE_UNAVAILABLE] The socket buffer is full.");
503                                 return E_RESOURCE_UNAVAILABLE;
504                         }
505
506                         SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Failed to send a request: %d, %s", errno, strerror(errno));
507                         return E_SYSTEM;
508                 }
509
510                 remain -= written;
511                 pData += written;
512         }
513
514         ReleaseFd(fd);
515
516         return r;
517 }
518
519 result
520 _IpcClient::SendSync(IPC::Message* pMessage)
521 {
522         result r = E_SUCCESS;
523
524         int messageId = 0;
525         int fd = -1;
526
527         char* pData = null;
528         int remain = 0;
529         int written = 0;
530         int readSize = 0;
531         char buffer[1024];
532         char* pEndOfMessage = null;
533
534         std::string message;
535
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.");
540
541         messageId = SyncMessage::GetMessageId(*pSyncMessage);
542
543         fd = AcquireFd();
544         SysTryReturnResult(NID_IO, fd != -1, E_SYSTEM, "Failed to get fd.");
545
546         pData = (char*) pSyncMessage->data();
547         remain = pSyncMessage->size();
548
549         while (remain > 0)
550         {
551                 written = write(fd, (char*) pData, remain);
552                 if (written < 0)
553                 {
554                         ReleaseFd(fd);
555
556                         if (errno == EAGAIN)
557                         {
558                                 SysLogException(NID_IO, E_RESOURCE_UNAVAILABLE, "[E_RESOURCE_UNAVAILABLE] The socket buffer is full.");
559                                 return E_RESOURCE_UNAVAILABLE;
560                         }
561
562                         SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Failed to send a request: %d, %s", errno, strerror(errno));
563                         return E_SYSTEM;
564                 }
565
566                 remain -= written;
567                 pData += written;
568         }
569
570         // Wait reply
571         struct pollfd pfd;
572
573         pfd.fd = fd;
574         pfd.events = POLLIN | POLLRDHUP;
575         pfd.revents = 0;
576
577         int ret = 0;
578
579         while (true)
580         {
581                 ret = poll(&pfd, 1, -1);
582                 if (ret < 0)
583                 {
584                         if (errno == EINTR)
585                         {
586                                 continue;
587                         }
588
589                         SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Failed to poll (%d, %s).", errno, strerror(errno));
590
591                         ReleaseFd(fd);
592                         return E_SYSTEM;
593                 }
594
595                 if (pfd.revents & POLLRDHUP)
596                 {
597                         SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] POLLRDHUP");
598
599                         ReleaseFd(fd);
600                         return E_SYSTEM;
601                 }
602
603                 if (pfd.revents & POLLIN)
604                 {
605                         readSize = read(fd, buffer, 1024);
606                 }
607
608                 if (readSize > 0)
609                 {
610                         message.append(buffer, readSize);
611                 }
612
613                 pEndOfMessage = (char*) IPC::Message::FindNext(message.data(), message.data() + message.size());
614                 if (pEndOfMessage)
615                 {
616                         pReply = new (std::nothrow) IPC::Message(message.data(), pEndOfMessage - message.data());
617                         if (pReply == null)
618                         {
619                                 SysLogException(NID_IO, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
620
621                                 ReleaseFd(fd);
622                                 return E_OUT_OF_MEMORY;
623                         }
624
625                         break;
626                 }
627         }
628
629         pReplyDeserializer = pSyncMessage->GetReplyDeserializer();
630         pReplyDeserializer->SerializeOutputParameters(*pReply);
631
632         delete pReply;
633         delete pReplyDeserializer;
634
635         ReleaseFd(fd);
636
637         return r;
638 }
639
640 result
641 _IpcClient::Send(IPC::Message* pMessage)
642 {
643         result r = E_SUCCESS;
644
645         SysAssertf(__pFdLock != null, "Not yet constructed. Construct() should be called before use.\n");
646
647         if (pMessage->is_sync())
648         {
649                 r = SendSync(pMessage);
650         }
651         else
652         {
653                 r = SendAsync(pMessage);
654         }
655
656         return r;
657 }
658
659 result
660 _IpcClient::SendRequest(IPC::Message* pMessage)
661 {
662         return Send(pMessage);
663 }
664
665 result
666 _IpcClient::SendRequest(const IPC::Message& message)
667 {
668         result r = E_SUCCESS;
669
670         SysAssertf(__pFdLock != null, "Not yet constructed. Construct() should be called before use.\n");
671
672         if (message.is_sync())
673         {
674                 r = SendSync(const_cast<IPC::Message*>(&message));
675         }
676         else
677         {
678                 r = SendAsync(const_cast<IPC::Message*>(&message));
679         }
680
681         return r;
682 }
683
684 } } //Tizen::Io