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