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