Merge "Fix SystemInfo cache" into tizen_2.1
[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 pkgId[256];
138         char appExecutableName[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         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 pkgId
180                 String pkgId = _AppInfo::GetPackageId();
181                 int length = (pkgId.GetLength() + 1) * sizeof(wchar_t);
182                 if (length > 255)
183                 {
184                         length = 255;
185                 }
186
187                 SysTryReturnResult(NID_IO, pkgId.GetLength() > 0, E_SYSTEM, "AppId dose not exist.");
188
189                 memcpy(helloMessage.pkgId, pkgId.GetPointer(), length);
190
191                 // Set an executableName
192                 String appExecutableName = _AppInfo::GetAppExecutableName();
193                 length = (appExecutableName.GetLength() + 1) * sizeof(wchar_t);
194                 if (length > 255)
195                 {
196                         length = 255;
197                 }
198
199                 if (appExecutableName.GetLength() != 0)
200                 {
201                         memcpy(helloMessage.appExecutableName, appExecutableName.GetPointer(), length);
202                 }
203         }
204
205         client = socket(AF_UNIX, SOCK_STREAM, 0);
206         SysTryCatch(NID_IO, client != -1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to create a socket : %s.", strerror(errno));
207
208         flags = fcntl(client, F_GETFL, 0);
209         ret = fcntl(client, F_SETFL, flags | O_NONBLOCK);
210         SysTryCatch(NID_IO, ret >= 0 , r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to set file status flags (%d, %s).",
211                                            errno, strerror(errno));
212
213         bzero(&server, sizeof(server));
214         server.sun_family = AF_UNIX;
215         strncpy(server.sun_path, socketName.c_str(), socketNameLength);
216         serverLen = sizeof(server);
217
218         ret = connect(client, (struct sockaddr*) &server, serverLen);
219         if (ret != 0)
220         {
221                 SysTryCatch(NID_IO, errno == EINPROGRESS, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to connect to server(%s) : %s",
222                                    socketName.c_str(), strerror(errno));
223
224                 fd_set rset;
225                 fd_set wset;
226                 struct timeval timeout;
227                 int length = 0;
228                 int error = 0;
229                 socklen_t socketLength = 0;
230
231                 FD_ZERO(&rset);
232                 FD_SET(client, &rset);
233                 wset = rset;
234                 timeout.tv_sec = 10;
235                 timeout.tv_usec = 0;
236
237                 while (true)
238                 {
239                         ret = select(client+1, &rset, &wset, NULL, &timeout);
240                         if (ret < 0)
241                         {
242                                 SysTryCatch(NID_IO, errno == EINTR , r = E_SYSTEM, E_SYSTEM, "[E_TIMEOUT] Failed to connect due to system error.");
243
244                                 continue;
245                         }
246                         else if (ret == 0)
247                         {
248                                 r = E_TIMEOUT;
249                                 SysLogException(NID_IO, E_TIMEOUT, "[E_TIMEOUT] Failed to connect due to timeout.");
250                                 goto CATCH;
251                         }
252                         else
253                         {
254                                 break;
255                         }
256                 }
257
258                 if (FD_ISSET(client, &rset) || FD_ISSET(client, &wset))
259                 {
260                         length = sizeof(error);
261                         ret = getsockopt(client, SOL_SOCKET, SO_ERROR, &error, &socketLength);
262                         SysTryCatch(NID_IO, ret >= 0 , r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to connect to server(%s) : %s",
263                                            socketName.c_str(), strerror(errno));
264                 }
265                 else
266                 {
267                         r = E_SYSTEM;
268                         SysLogException(NID_IO, E_SYSTEM, "[E_TIMEOUT] Failed to connect due to system error.");
269                         goto CATCH;
270                 }
271         }
272
273         ret = fcntl(client, F_SETFL, flags);
274         SysTryCatch(NID_IO, ret >= 0 , r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to set file status flags (%d, %s).",
275                                            errno, strerror(errno));
276
277         write(client, &helloMessage, sizeof(helloMessage));
278
279         if (forReverse)
280         {
281                 GError* pGError = null;
282                 GSource* pGSource = null;
283                 ;
284                 GIOChannel* pChannel = g_io_channel_unix_new(client);
285                 GMainContext* pGMainContext = g_main_context_default();
286
287                 g_io_channel_set_encoding(pChannel, null, &pGError);
288                 g_io_channel_set_flags(pChannel, G_IO_FLAG_NONBLOCK, &pGError);
289                 g_io_channel_set_close_on_unref(pChannel, TRUE);
290
291                 pGSource = g_io_create_watch(pChannel, (GIOCondition) (G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP));
292                 g_source_set_callback(pGSource, (GSourceFunc) OnReadMessage, this, null);
293                 g_source_attach(pGSource, pGMainContext);
294
295                 g_io_channel_unref(pChannel);
296                 __pReverseSource = pGSource;
297         }
298         else
299         {
300                 ++__fdCount;
301
302                 ReleaseFd(client);
303         }
304
305         return r;
306
307 CATCH:
308         if (client != -1)
309         {
310                 close(client);
311         }
312
313         return r;
314 }
315
316 gboolean
317 _IpcClient::OnReadMessage(GIOChannel* source, GIOCondition condition, gpointer data)
318 {
319
320         _IpcClient* pIpcClient = (_IpcClient*) data;
321
322         return pIpcClient->HandleReceivedMessage(source, condition);
323 }
324
325 gboolean
326 _IpcClient::HandleReceivedMessage(GIOChannel* source, GIOCondition condition)
327 {
328         GError* pGError = null;
329         GIOStatus status;
330         IPC::Message* pMessage = null;
331
332         if (condition & G_IO_HUP)
333         {
334                 SysLog(NID_IO, "G_IO_HUP, the connection is closed.");
335
336                 g_source_destroy(__pReverseSource);
337                 g_source_unref(__pReverseSource);
338                 __pReverseSource = null;
339
340                 if (__pListener)
341                 {
342                         __pListener->OnIpcServerDisconnected(*this);
343                 }
344
345                 return FALSE;
346         }
347         else if (condition & G_IO_IN)
348         {
349                 gsize readSize = 0;
350                 const char* pStart = null;
351                 const char* pEnd = null;
352                 const char* pEndOfMessage = null;
353
354                 while (true)
355                 {
356                         pGError = null;
357                         status = g_io_channel_read_chars(source, (char*) __messageBuffer, __MAX_MESSAGE_BUFFER_SIZE, &readSize, &pGError);
358                         if (status == G_IO_STATUS_EOF || status == G_IO_STATUS_ERROR)
359                         {
360                                 if (status == G_IO_STATUS_EOF)
361                                 {
362                                         SysLog(NID_IO, "G_IO_STATUS_EOF, the connection is closed.");
363                                 }
364                                 else
365                                 {
366                                         SysLog(NID_IO, "G_IO_STATUS_ERROR, the connection is closed. ");
367                                 }
368
369                                 pGError = null;
370
371                                 g_io_channel_shutdown(source, FALSE, &pGError);
372
373                                 g_source_destroy(__pReverseSource);
374                                 g_source_unref(__pReverseSource);
375                                 __pReverseSource = null;
376
377                                 if (__pListener)
378                                 {
379                                         __pListener->OnIpcServerDisconnected(*this);
380                                 }
381
382                                 return FALSE;
383                         }
384
385                         if (readSize == 0)
386                         {
387                                 break;
388                         }
389
390                         if (__pending.empty())
391                         {
392                                 pStart = __messageBuffer;
393                                 pEnd = pStart + readSize;
394                         }
395                         else
396                         {
397                                 __pending.append(__messageBuffer, readSize);
398                                 pStart = __pending.data();
399                                 pEnd = pStart + __pending.size();
400                         }
401
402                         while (true)
403                         {
404                                 pEndOfMessage = IPC::Message::FindNext(pStart, pEnd);
405                                 if (pEndOfMessage == null)
406                                 {
407                                         __pending.assign(pStart, pEnd - pStart);
408                                         break;
409                                 }
410
411                                 pMessage = new (std::nothrow) IPC::Message(pStart, pEndOfMessage - pStart);
412                                 SysTryReturn(NID_IO, pMessage != null, FALSE, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
413
414                                 if (__pListener)
415                                 {
416                                         __pListener->OnIpcResponseReceived(*this, *pMessage);
417                                 }
418
419                                 delete pMessage;
420
421                                 pStart = pEndOfMessage;
422                         }
423                 }
424         }
425         else
426         {
427                 // empty statement.
428         }
429
430         return TRUE;
431 }
432
433 int
434 _IpcClient::AcquireFd(void)
435 {
436         result r = E_SUCCESS;
437         int fd = -1;
438
439         while (fd == -1)
440         {
441                 __pFdLock->Acquire();
442                 if (__fds.size() == 0)
443                 {
444                         __pFdLock->Release();
445                         r = MakeConnection(false);
446                         SysTryReturn(NID_IO, !IsFailed(r), -1, r, "[%s] Failed to connect to the server.", GetErrorMessage(r));
447
448                         continue;
449                 }
450
451                 fd = __fds.back();
452                 __fds.pop_back();
453
454                 __pFdLock->Release();
455         }
456
457         return fd;
458 }
459
460 void
461 _IpcClient::ReleaseFd(int fd)
462 {
463         __pFdLock->Acquire();
464
465         __fds.push_back(fd);
466
467         __pFdLock->Release();
468 }
469
470 result
471 _IpcClient::SendAsync(IPC::Message* pMessage)
472 {
473         result r = E_SUCCESS;
474
475         int fd = -1;
476         char* pData = null;
477         int remain = 0;
478         int written = 0;
479
480         pData = (char*) pMessage->data();
481         remain = pMessage->size();
482
483         fd = AcquireFd();
484         SysTryReturnResult(NID_IO, fd != -1, E_SYSTEM, "Failed to get fd.");
485
486         while (remain > 0)
487         {
488                 written = write(fd, (char*) pData, remain);
489                 remain -= written;
490                 pData += written;
491         }
492
493         ReleaseFd(fd);
494
495         return r;
496 }
497
498 result
499 _IpcClient::SendSync(IPC::Message* pMessage)
500 {
501         result r = E_SUCCESS;
502
503         int messageId = 0;
504         int fd = -1;
505
506         char* pData = null;
507         int remain = 0;
508         int written = 0;
509         int readSize = 0;
510         char buffer[1024];
511         char* pEndOfMessage = null;
512
513         std::string message;
514
515         struct pollfd pfd;
516
517         IPC::Message* pReply = null;
518         MessageReplyDeserializer* pReplyDeserializer = null;
519         IPC::SyncMessage* pSyncMessage = dynamic_cast <IPC::SyncMessage*>(pMessage);
520         SysTryReturnResult(NID_IO, pSyncMessage != null, E_INVALID_ARG, "pMessage is not a sync message.");
521
522         messageId = SyncMessage::GetMessageId(*pSyncMessage);
523
524         fd = AcquireFd();
525         SysTryReturnResult(NID_IO, fd != -1, E_SYSTEM, "Failed to get fd.");
526
527         pData = (char*) pSyncMessage->data();
528         remain = pSyncMessage->size();
529
530         while (remain > 0)
531         {
532                 written = write(fd, (char*) pData, remain);
533                 remain -= written;
534                 pData += written;
535         }
536
537         // Wait reply
538         pfd.fd = fd;
539         pfd.events = POLLIN | POLLRDHUP;
540         pfd.revents = 0;
541
542         int ret = 0;
543
544         while (true)
545         {
546                 ret = poll(&pfd, 1, -1);
547                 if (ret < 0)
548                 {
549                         if (errno == EINTR)
550                         {
551                                 continue;
552                         }
553
554                         SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Failed to poll (%d, %s).", errno, strerror(errno));
555                         return E_SYSTEM;
556                 }
557
558                 if (pfd.revents & POLLRDHUP)
559                 {
560                         SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] POLLRDHUP");
561                         return E_SYSTEM;
562                 }
563
564                 if (pfd.revents & POLLIN)
565                 {
566                         readSize = read(fd, buffer, 1024);
567                 }
568
569                 if (readSize > 0)
570                 {
571                         message.append(buffer, readSize);
572                 }
573
574                 pEndOfMessage = (char*) IPC::Message::FindNext(message.data(), message.data() + message.size());
575                 if (pEndOfMessage)
576                 {
577                         pReply = new (std::nothrow) IPC::Message(message.data(), pEndOfMessage - message.data());
578                         SysTryReturnResult(NID_IO, pReply != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
579                         break;
580                 }
581         }
582
583         pReplyDeserializer = pSyncMessage->GetReplyDeserializer();
584         pReplyDeserializer->SerializeOutputParameters(*pReply);
585
586         delete pReply;
587         delete pReplyDeserializer;
588
589         ReleaseFd(fd);
590
591         return r;
592 }
593
594 result
595 _IpcClient::Send(IPC::Message* pMessage)
596 {
597         result r = E_SUCCESS;
598
599         SysAssertf(__pFdLock != null, "Not yet constructed. Construct() should be called before use.\n");
600
601         if (pMessage->is_sync())
602         {
603                 r = SendSync(pMessage);
604         }
605         else
606         {
607                 r = SendAsync(pMessage);
608         }
609
610         return r;
611 }
612
613 result
614 _IpcClient::SendRequest(IPC::Message* pMessage)
615 {
616         return Send(pMessage);
617 }
618
619 result
620 _IpcClient::SendRequest(const IPC::Message& message)
621 {
622         result r = E_SUCCESS;
623
624         SysAssertf(__pFdLock != null, "Not yet constructed. Construct() should be called before use.\n");
625
626         if (message.is_sync())
627         {
628                 r = SendSync(const_cast<IPC::Message*>(&message));
629         }
630         else
631         {
632                 r = SendAsync(const_cast<IPC::Message*>(&message));
633         }
634
635         return r;
636 }
637
638 } } //Tizen::Io