sync with master
[platform/framework/native/appfw.git] / src / server / io / FIo_IpcServer.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_IpcServer.cpp
20  * @brief This is the implementation file for the _IpcServer class.
21  *
22  */
23
24 #include <cstdio>
25 #include <cstdlib>
26 #include <cstring>
27 #include <cerrno>
28 #include <iostream>
29 #include <new>
30
31 #include <unistd.h>
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <sys/stat.h>
35 #include <sys/un.h>
36
37 #include <ipc/ipc_message.h>
38
39 #include <FBaseRtMutex.h>
40 #include <FBaseSysLog.h>
41 #include <FBase_StringConverter.h>
42 #include <FBaseRt_EventDispatcher.h>
43
44 #include "FIo_IIpcServerEventListener.h"
45 #include "FIo_IpcServer.h"
46
47 using namespace std;
48 using namespace IPC;
49 using namespace Tizen::Base;
50 using namespace Tizen::Base::Runtime;
51 using namespace Tizen::App;
52
53 namespace Tizen { namespace Io
54 {
55
56 _IpcServer::_ChannelInfo::_ChannelInfo(void)
57         : pClientInfo(null)
58         , pGIOChannel(null)
59         , pGSource(null)
60         , destroySource(true)
61 {
62
63 }
64
65 _IpcServer::_ChannelInfo::~_ChannelInfo(void)
66 {
67         if (pGIOChannel != null)
68         {
69                 g_io_channel_unref(pGIOChannel);
70         }
71
72         if (pGSource != null)
73         {
74                 if (destroySource)
75                 {
76                         g_source_destroy(pGSource);
77                 }
78
79                 g_source_unref(pGSource);
80         }
81 }
82
83 _IpcServer::_ClientInfo::_ClientInfo(void)
84         : clientId(-1)
85         , pIpcServer(null)
86         , pReverseChannel(null)
87 {
88
89 }
90
91 _IpcServer::_ClientInfo::~_ClientInfo(void)
92 {
93         if (pReverseChannel != null)
94         {
95                 g_io_channel_unref(pReverseChannel);
96         }
97
98         channels.clear();
99 }
100
101 _IpcServer::_IpcServer(void)
102         : __name("")
103         , __runOnCallerThread(false)
104         , __pEventDispatcher(null)
105         , __pListener(null)
106         , __handlerThread(0)
107         , __pHandlerGMainContext(null)
108         , __pHandlerGMainLoop(null)
109         , __pConnectGSource(null)
110         , __pCurrentChannel(null)
111         , __pCurrentClientInfo(null)
112 {
113         __messageBuffer[0] = '\0';
114 }
115
116
117 _IpcServer::~_IpcServer(void)
118 {
119         if (__pConnectGSource != null)
120         {
121                 g_source_destroy(__pConnectGSource);
122                 g_source_unref(__pConnectGSource);
123                 __pConnectGSource = null;
124         }
125
126         if (!__runOnCallerThread)
127         {
128                 if (__pEventDispatcher)
129                 {
130                         delete __pEventDispatcher;
131                         __pEventDispatcher = null;
132                 }
133
134                 if (__pHandlerGMainLoop)
135                 {
136                         g_main_loop_unref(__pHandlerGMainLoop);
137                         __pHandlerGMainLoop = null;
138                 }
139
140                 if (__pHandlerGMainContext)
141                 {
142                         g_main_context_unref(__pHandlerGMainContext);
143                         __pHandlerGMainContext = null;
144                 }
145         }
146
147         // clean-up clients
148         __clients.clear();
149 }
150
151 result
152 _IpcServer::Construct(const String& name, const _IIpcServerEventListener& listener, bool runOnCallerThread)
153 {
154         result r = E_SUCCESS;
155
156         GIOChannel* pGIOChannel = null;
157         GSource* pGSource = null;
158
159         struct sockaddr_un serverAddress;
160         int serverSocket = -1;
161         int serverLen = 0;
162         int ret = 0;
163         std::string socketName;
164         char* pName = null;
165         size_t socketNameLength = 0;
166
167         __name = name;
168         __pListener = const_cast <_IIpcServerEventListener*>(&listener);
169         __runOnCallerThread = runOnCallerThread;
170
171         pName = _StringConverter::CopyToCharArrayN(name);
172         SysTryReturnResult(NID_IO, pName != null, E_OUT_OF_MEMORY, "Not enough memory");
173
174         socketName.append("/tmp/");
175         socketName.append(pName);
176
177         delete[] pName;
178
179         socketNameLength = socketName.size() + 1;
180         SysTryReturnResult(NID_IO, socketNameLength < 108, E_INVALID_ARG, "Server name is too long");
181
182         if (!__runOnCallerThread)
183         {
184                 __pHandlerGMainContext = g_main_context_new();
185                 __pHandlerGMainLoop = g_main_loop_new(__pHandlerGMainContext, FALSE);
186
187         }
188         else
189         {
190                 __pHandlerGMainContext = g_main_context_get_thread_default();
191                 if (__pHandlerGMainContext == null) // is global?
192                 {
193                         __pHandlerGMainContext = g_main_context_default();
194                         if (__pHandlerGMainContext == null)
195                         {
196                                 return E_SYSTEM;
197                         }
198                 }
199         }
200
201         ret = unlink(socketName.c_str());
202         SysTryLog(NID_IO, ret == 0, "Unlink a socket has failed.. but it is not a problem.");
203
204         serverSocket = socket(AF_UNIX, SOCK_STREAM, 0);
205         SysTryReturnResult(NID_IO, serverSocket != -1, E_SYSTEM, "Failed to create a socket.");
206
207         bzero(&serverAddress, sizeof(serverAddress));
208         serverAddress.sun_family = AF_UNIX;
209         strncpy(serverAddress.sun_path, socketName.c_str(), socketNameLength);
210         serverLen = sizeof(serverAddress);
211
212         ret = bind(serverSocket, (const struct sockaddr*) &serverAddress, serverLen);
213         SysTryCatch(NID_IO, ret != -1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to bind a socket(%d, %s): %s", serverSocket,
214                            socketName.c_str(), strerror(errno));
215
216         ret = chmod(socketName.c_str(), 0666);
217         SysTryCatch(NID_IO, ret == 0, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to change permission of a socket(%d, %s): %s", serverSocket,
218                            socketName.c_str(), strerror(errno));
219
220         listen(serverSocket, 15);
221
222         pGIOChannel = g_io_channel_unix_new(serverSocket);
223         SysTryCatch(NID_IO, pGIOChannel != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Not enough memory.");
224
225         // socket will be closed when pGIOChannel is deleted.
226         g_io_channel_set_close_on_unref(pGIOChannel, TRUE);
227         serverSocket = -1;
228
229         pGSource = g_io_create_watch(pGIOChannel, (GIOCondition) (G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP));
230         SysTryCatch(NID_IO, pGSource != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
231                            "[E_OUT_OF_MEMORY] Failed to create watch for socket.");
232
233         // channel will be delete when pGSource is deleted.
234         g_io_channel_unref(pGIOChannel);
235         pGIOChannel = null;
236
237         g_source_set_callback(pGSource, (GSourceFunc) OnConnectionRequest, this, NULL);
238         g_source_attach(pGSource, __pHandlerGMainContext);
239
240         if (__runOnCallerThread)
241         {
242                 __pListener->OnIpcServerStarted(*this);
243         }
244         else
245         {
246                 ret = pthread_create(&__handlerThread, null, &ThreadProc, (void*) this);
247                 SysTryCatch(NID_IO, ret == 0, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to an IPC thread");
248         }
249
250         __pConnectGSource = pGSource;
251
252         return E_SUCCESS;
253
254 CATCH:
255         if (pGIOChannel != null)
256         {
257                 g_io_channel_unref(pGIOChannel);
258         }
259
260         if (serverSocket != -1)
261         {
262                 close(serverSocket);
263         }
264
265         if (runOnCallerThread && __pHandlerGMainContext)
266         {
267                 g_main_context_unref(__pHandlerGMainContext);
268                 __pHandlerGMainContext = null;
269         }
270
271         return r;
272 }
273
274 struct HelloMessage
275 {
276         int pid;
277         bool reverse;  // true if the connection is for reverse message
278         char pkgId[256];
279         char appExecutableName[256];
280 };
281
282 gboolean
283 _IpcServer::OnConnectionRequest(GIOChannel* source, GIOCondition condition, gpointer data)
284 {
285         _IpcServer* pIpcServer = (_IpcServer*) data;
286         GError* pGError = null;
287         HelloMessage helloMessage;
288         _ClientInfo* pClientInfo = null;
289         _ChannelInfo* pChannelInfo = null;
290         GSource* pGSource = null;
291         GIOChannel* pChannel = null;
292
293         int server = -1;
294         int client = -1;
295         struct sockaddr_un clientAddress;
296         socklen_t clientLen = sizeof(clientAddress);
297
298         SysAssertf(pIpcServer != null, "Not yet constructed. Construct() should be called before use.\n");
299         SysAssertf(pIpcServer->__pListener != null, "Listener is null.\n");
300
301         server = g_io_channel_unix_get_fd(source);
302
303         client = accept(server, (struct sockaddr*) &clientAddress, &clientLen);
304         SysTryCatch(NID_IO, client != -1, , E_SYSTEM, "[E_SYSTEM] Accept failed.");
305
306         read(client, &helloMessage, sizeof(helloMessage));
307         helloMessage.pkgId[255] = '\0';
308         helloMessage.appExecutableName[255] = '\0';
309
310         pChannel = g_io_channel_unix_new(client);
311         SysTryCatch(NID_IO, pChannel != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Not enough memory.");
312
313         g_io_channel_set_encoding(pChannel, NULL, &pGError);
314         g_io_channel_set_flags(pChannel, G_IO_FLAG_NONBLOCK, &pGError);
315
316         g_io_channel_set_close_on_unref(pChannel, TRUE);
317         client = -1;
318
319         pClientInfo = pIpcServer->__clients[helloMessage.pid];
320         if (pClientInfo == null) // first connection request from this client
321         {
322                 pClientInfo = new (std::nothrow) _ClientInfo;
323                 SysTryCatch(NID_IO, pClientInfo != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Not enough memory.");
324
325                 pClientInfo->pIpcServer = pIpcServer;
326                 pClientInfo->clientId = helloMessage.pid;
327                 pClientInfo->pkgId.Append((wchar_t*) helloMessage.pkgId);
328                 pClientInfo->appExecutableName.Append((wchar_t*) helloMessage.appExecutableName);
329                 pClientInfo->pReverseChannel = null;
330
331                 pIpcServer->__clients[helloMessage.pid] = pClientInfo;
332
333                 pIpcServer->__pCurrentClientInfo = pClientInfo;
334                 pIpcServer->__pListener->OnIpcClientConnected(*pIpcServer, helloMessage.pid);
335                 pIpcServer->__pCurrentClientInfo = null;
336         }
337
338         if (helloMessage.reverse)
339         {
340                 pClientInfo->pReverseChannel = pChannel;
341         }
342         else
343         {
344                 pChannelInfo = new (std::nothrow) _ChannelInfo;
345                 SysTryCatch(NID_IO, pChannelInfo != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Not enough memory.");
346
347                 pGSource = g_io_create_watch(pChannel, (GIOCondition) (G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP));
348                 g_source_set_callback(pGSource, (GSourceFunc) OnReadMessage, pChannelInfo, NULL);
349                 g_source_attach(pGSource, pIpcServer->__pHandlerGMainContext);
350
351                 pChannelInfo->pClientInfo = pClientInfo;
352                 pChannelInfo->pGIOChannel = pChannel;
353                 pChannelInfo->pGSource = pGSource;
354
355                 pClientInfo->channels.push_back(pChannelInfo);
356         }
357
358         return true;
359
360 CATCH:
361         if (pChannel != null)
362         {
363                 g_io_channel_unref(pChannel);
364         }
365
366         if (client != -1)
367         {
368                 close(client);
369         }
370
371         return true;
372 }
373
374 int
375 _IpcServer::GetClientId(void) const
376 {
377         if (__pCurrentClientInfo)
378         {
379                 return __pCurrentClientInfo->clientId;
380         }
381
382         return -1;
383 }
384
385 int
386 _IpcServer::GetClientProcessId(void) const
387 {
388         if (__pCurrentClientInfo)
389         {
390                 return __pCurrentClientInfo->clientId;
391         }
392
393         return -1;
394 }
395
396 String
397 _IpcServer::GetClientAppId(void) const
398 {
399         static String nullString;
400
401         if (__pCurrentClientInfo)
402         {
403                 return __pCurrentClientInfo->pkgId;
404         }
405
406         return nullString;
407 }
408
409 String
410 _IpcServer::GetClientAppExecutableName(void) const
411 {
412         static String nullString;
413
414         if (__pCurrentClientInfo)
415         {
416                 return __pCurrentClientInfo->appExecutableName;
417         }
418
419         return nullString;
420 }
421
422 AppId
423 _IpcServer::GetClientApplicationId(void) const
424 {
425         static String nullString;
426
427         if (__pCurrentClientInfo)
428         {
429                 String appId(__pCurrentClientInfo->pkgId);
430                 appId.Append(L'.');
431                 appId.Append(__pCurrentClientInfo->appExecutableName);
432
433                 return appId;
434         }
435
436         return nullString;
437 }
438
439 gboolean
440 _IpcServer::HandleReceivedMessage(GIOChannel* source, GIOCondition condition, gpointer data)
441 {
442         GError* pGError = NULL;
443         GIOStatus status;
444         IPC::Message* pMessage = NULL;
445         _ChannelInfo* pChannelInfo = (_ChannelInfo*) data;
446         _ClientInfo* pClientInfo = pChannelInfo->pClientInfo;
447
448         if (condition & G_IO_HUP)
449         {
450                 SysLog(NID_IO, "Connection closed");
451                 int clientId = pClientInfo->clientId;
452
453                 g_io_channel_shutdown(source, FALSE, &pGError);
454
455                 for (unsigned int i = 0; i < pClientInfo->channels.size(); i++)
456                 {
457                         if (pChannelInfo == pClientInfo->channels[i])
458                         {
459                                 pClientInfo->channels.erase(pClientInfo->channels.begin() + i);
460
461                                 // Do not destroy a source in a dispatch callback
462                                 // because main loop will do it if the callback return FALSE.
463                                 pChannelInfo->destroySource = false;
464                                 delete pChannelInfo;
465
466                                 break;
467                         }
468                 }
469
470                 if (pClientInfo->channels.size() == 0)
471                 {
472                         SysLog(NID_IO, "All connections of client(%d) are closed. delete client info", clientId);
473
474                         __pListener->OnIpcClientDisconnected(*this, clientId);
475
476                         __clients[clientId] = null;
477
478                         delete pClientInfo;
479                 }
480
481                 return FALSE;
482         }
483         else if (condition & G_IO_IN)
484         {
485                 gsize readSize = 0;
486                 const char* pStart = NULL;
487                 const char* pEnd = NULL;
488                 const char* pEndOfMessage = NULL;
489
490                 while (true)
491                 {
492                         pGError = null;
493                         status = g_io_channel_read_chars(source, (char*) __messageBuffer, __MAX_MESSAGE_BUFFER_SIZE, &readSize, &pGError);
494                         if (status != G_IO_STATUS_NORMAL)
495                         {
496                                 if (status == G_IO_STATUS_EOF || status == G_IO_STATUS_ERROR)
497                                 {
498                                         if (status == G_IO_STATUS_EOF)
499                                         {
500                                                 SysLog(NID_IO, "G_IO_STATUS_EOF, the connection is closed.");
501                                         }
502                                         else
503                                         {
504                                                 SysLog(NID_IO, "G_IO_STATUS_ERROR, the connection is closed. ");
505                                         }
506
507                                         pGError = null;
508                                         g_io_channel_shutdown(source, FALSE, &pGError);
509
510                                         int clientId = pClientInfo->clientId;
511
512                                         for (unsigned int i = 0; i < pClientInfo->channels.size(); i++)
513                                         {
514                                                 if (pChannelInfo == pClientInfo->channels[i])
515                                                 {
516                                                         pClientInfo->channels.erase(pClientInfo->channels.begin() + i);
517
518                                                         pChannelInfo->destroySource = false;
519                                                         delete pChannelInfo;
520                                                         break;
521                                                 }
522                                         }
523
524                                         if (pClientInfo->channels.size() == 0)
525                                         {
526                                                 SysLog(NID_IO, "All connections of client(%d) are closed normally by the client.", clientId);
527
528                                                 if (__pListener)
529                                                 {
530                                                         __pListener->OnIpcClientDisconnected(*this, clientId);
531                                                 }
532
533                                                 __clients[clientId] = null;
534
535                                                 delete pClientInfo;
536                                         }
537
538                                         return FALSE;
539                                 }
540                         }
541
542                         if (readSize == 0)
543                         {
544                                 break;
545                         }
546
547                         if (__pending.empty())
548                         {
549                                 pStart = __messageBuffer;
550                                 pEnd = pStart + readSize;
551                         }
552                         else
553                         {
554                                 __pending.append(__messageBuffer, readSize);
555                                 pStart = __pending.data();
556                                 pEnd = pStart + __pending.size();
557                         }
558
559                         while (true)
560                         {
561                                 pEndOfMessage = IPC::Message::FindNext(pStart, pEnd);
562                                 if (pEndOfMessage == NULL)
563                                 {
564                                         __pending.assign(pStart, pEnd - pStart);
565                                         break;
566                                 }
567
568                                 pMessage = new (std::nothrow) IPC::Message(pStart, pEndOfMessage - pStart);
569                                 SysTryReturn(NID_IO, pMessage != null, FALSE, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
570
571                                 __pCurrentChannel = source;
572
573                                 if (__pListener)
574                                 {
575                                         __pListener->OnIpcRequestReceived(*this, *pMessage);
576                                 }
577
578                                 delete pMessage;
579
580                                 __pCurrentChannel = NULL;
581
582                                 pStart = pEndOfMessage;
583                         }
584                 }
585         }
586         else
587         {
588                 // empty statement
589         }
590
591         return TRUE;
592 }
593
594 gboolean
595 _IpcServer::OnReadMessage(GIOChannel* source, GIOCondition condition, gpointer data)
596 {
597         gboolean ret = FALSE;
598         _ChannelInfo* pChannelInfo = (_ChannelInfo*) data;
599         _ClientInfo* pClientInfo = pChannelInfo->pClientInfo;
600         _IpcServer* pIpcServer = (_IpcServer*) pClientInfo->pIpcServer;
601
602         pIpcServer->__pCurrentClientInfo = pClientInfo;
603         ret = pIpcServer->HandleReceivedMessage(source, condition, data);
604         pIpcServer->__pCurrentClientInfo = null;
605
606         return ret;
607 }
608
609 void*
610 _IpcServer::ThreadProc(void* pParam)
611 {
612         _IpcServer* pIpcServer = (_IpcServer*) pParam;
613         if (pIpcServer != NULL)
614         {
615                 pIpcServer->Run(NULL);
616         }
617
618         return NULL;
619 }
620
621 void
622 _IpcServer::Run(void* pParam)
623 {
624         result r = E_SUCCESS;
625
626         if (__pListener == null)
627         {
628                 return;
629         }
630
631         __pEventDispatcher = new (std::nothrow) _EventDispatcher;
632         SysTryReturnVoidResult(NID_IO, __pEventDispatcher != null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
633
634         r = __pEventDispatcher->Construct(__pHandlerGMainContext);
635         if (IsFailed(r))
636         {
637                 delete __pEventDispatcher;
638                 __pEventDispatcher = null;
639         }
640
641         __pListener->OnIpcServerStarted(*this);
642
643         g_main_loop_run(__pHandlerGMainLoop);
644
645         __pListener->OnIpcServerStopped(*this);
646 }
647
648 result
649 _IpcServer::Start(void)
650 {
651         return E_SUCCESS;
652 }
653
654 String
655 _IpcServer::GetName(void) const
656 {
657         return __name;
658 }
659
660 result
661 _IpcServer::Stop(void)
662 {
663         result r = E_SUCCESS;
664         int ret = 0;
665
666         SysTryReturnResult(NID_IO, __pListener != null, E_SYSTEM, "Listener is null.");
667
668         if (!__runOnCallerThread)
669         {
670                 pthread_t self = pthread_self();
671
672                 if (__pHandlerGMainLoop)
673                 {
674                         g_main_loop_quit(__pHandlerGMainLoop);
675                 }
676
677                 if (__handlerThread != self)
678                 {
679                         ret = pthread_join(__handlerThread, null);
680                         SysTryLog(NID_IO, ret == 0, "Join an IPC thread returns an error");
681                 }
682         }
683         else
684         {
685                 __pListener->OnIpcServerStopped(*this);
686         }
687
688         return r;
689 }
690
691 bool
692 _IpcServer::Send(IPC::Message* msg)
693 {
694         gsize remain = 0;
695         gsize written = 0;
696         char* pData = NULL;
697         GError* pGError = NULL;
698
699
700         pData = (char*) msg->data();
701         remain = msg->size();
702
703         if (msg->is_reply())
704         {
705                 while (remain > 0)
706                 {
707                         pGError = NULL;
708                         g_io_channel_write_chars(__pCurrentChannel, (char*) pData, remain, &written, &pGError);
709
710                         remain -= written;
711                         pData += written;
712                 }
713
714                 g_io_channel_flush(__pCurrentChannel, &pGError);
715         }
716         else
717         {
718                 // empty statement;
719         }
720
721         return true;
722 }
723
724 result
725 _IpcServer::SendResponse(int client, IPC::Message* pMessage)
726 {
727         result r = E_SUCCESS;
728         gsize remain = 0;
729         gsize written = 0;
730         char* pData = null;
731         GError* pGError = null;
732         _ClientInfo* pClientInfo = null;
733
734         SysTryReturn(NID_IO, client >= 0 && pMessage != null, false, E_INVALID_ARG,
735                                 "[E_INVALID_ARG] pMessage(0x%x) is null or clinet(%d) < 0", pMessage,
736                                 client);
737         SysTryCatch(NID_IO, !pMessage->is_sync(), r = E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] Can't send sync. messagee.");
738
739         pClientInfo = __clients[client];
740         SysTryCatch(NID_IO, pClientInfo != null, r = E_INVALID_ARG, E_INVALID_ARG,
741                            "[E_INVALID_ARG] client(%d) has not been registered.",
742                            client);
743
744         pData = (char*) pMessage->data();
745         remain = pMessage->size();
746
747         while (remain > 0)
748         {
749                 pGError = NULL;
750                 g_io_channel_write_chars(pClientInfo->pReverseChannel, (char*) pData, remain, &written, &pGError);
751                 SysTryCatch(NID_IO, pGError == null, , E_SYSTEM, "[E_SYSTEM] Error occurred during writing message to socket.");
752
753                 remain -= written;
754                 pData += written;
755         }
756
757         g_io_channel_flush(pClientInfo->pReverseChannel, &pGError);
758
759         delete pMessage;
760
761         return E_SUCCESS;
762
763 CATCH:
764         delete pMessage;
765         return r;
766 }
767
768 result
769 _IpcServer::SendResponse(int client, const IPC::Message& message)
770 {
771         result r = E_SUCCESS;
772         gsize remain = 0;
773         gsize written = 0;
774         char* pData = null;
775         GError* pGError = null;
776         _ClientInfo* pClientInfo = null;
777
778         SysTryReturn(NID_IO, client >= 0, false, E_INVALID_ARG, "[E_INVALID_ARG] clinet(%d) < 0", client);
779         SysTryCatch(NID_IO, !message.is_sync(), r = E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] Can't send sync. messagee.");
780
781         pClientInfo = __clients[client];
782         SysTryCatch(NID_IO, pClientInfo != null, r = E_INVALID_ARG, E_INVALID_ARG,
783                            "[E_INVALID_ARG] client(%d) has not been registered.",
784                            client);
785
786         pData = (char*) message.data();
787         remain = message.size();
788
789         while (remain > 0)
790         {
791                 pGError = NULL;
792                 g_io_channel_write_chars(pClientInfo->pReverseChannel, (char*) pData, remain, &written, &pGError);
793                 SysTryCatch(NID_IO, pGError == null, , E_SYSTEM, "[E_SYSTEM] Error occurred during writing message to socket.");
794
795                 remain -= written;
796                 pData += written;
797         }
798
799         g_io_channel_flush(pClientInfo->pReverseChannel, &pGError);
800
801         return E_SUCCESS;
802
803 CATCH:
804         return r;
805 }
806
807 } } // Tizen::Io