merge with master
authorJinkun Jang <jinkun.jang@samsung.com>
Fri, 15 Mar 2013 16:16:39 +0000 (01:16 +0900)
committerJinkun Jang <jinkun.jang@samsung.com>
Fri, 15 Mar 2013 16:16:39 +0000 (01:16 +0900)
20 files changed:
CMakeLists.txt
inc/ChannelService.h
inc/FIo_ChannelCAppStub.h [new file with mode: 0644]
inc/FIo_ChannelService.h [new file with mode: 0644]
inc/FIo_ChannelServiceStub.h [new file with mode: 0644]
inc/FIo_ChannelWebAppStub.h [new file with mode: 0644]
inc/FIo_MessagePortService.h
inc/FIo_MessagePortStub.h
inc/IIpcServerEventListener.h [new file with mode: 0644]
inc/IpcServer.h [new file with mode: 0644]
manifest.xml
osp-channel-service.manifest
packaging/osp-channel-service.spec
src/FIo_ChannelCAppStub.cpp [new file with mode: 0644]
src/FIo_ChannelService.cpp [new file with mode: 0644]
src/FIo_ChannelServiceStub.cpp [new file with mode: 0644]
src/FIo_ChannelWebAppStub.cpp [new file with mode: 0644]
src/FIo_MessagePortService.cpp
src/FIo_MessagePortStub.cpp
src/IpcServer.cpp [new file with mode: 0644]

index 3ee79a5..5556a4e 100644 (file)
@@ -7,12 +7,18 @@ SET(CMAKE_EXECUTABLE_SUFFIX ".exe")
 SET(EXECUTABLE_OUTPUT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/output")
 
 INCLUDE_DIRECTORIES (
+       /usr/include
        /usr/include/glib-2.0
        /usr/lib/glib-2.0/include
+       /usr/include/libsoup-2.4
+       /usr/include/dlog
+       /usr/include/appfw
+       /usr/include/openssl
        /usr/include/osp
        /usr/include/osp/app
        /usr/include/osp/base
        /usr/include/osp/io
+       /usr/include/osp/server
        /usr/include/chromium
        inc
        )
@@ -20,8 +26,13 @@ INCLUDE_DIRECTORIES (
 SET (${this_target}_SOURCE_FILES
        src/ChannelService.cpp
        src/ChannelServiceEntry.cpp
+       src/FIo_ChannelService.cpp
+       src/FIo_ChannelServiceStub.cpp
+       src/FIo_ChannelCAppStub.cpp
+       src/FIo_ChannelWebAppStub.cpp
        src/FIo_MessagePortStub.cpp
        src/FIo_MessagePortService.cpp
+       src/IpcServer.cpp
        )
 
 ## SET EXTRA COMPILER FLAGS
@@ -34,13 +45,26 @@ SET(CMAKE_C_FLAGS "${OSP_DEBUG_FLAGS} ${OSP_OPT_FLAGS} ${CMAKE_C_FLAGS} ${EXTRA_
 SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
 SET(CMAKE_CXX_FLAGS "${OSP_DEBUG_FLAGS} ${OSP_OPT_FLAGS} ${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS} ${OSP_COMPILER_FLAGS}")
 
+SET(CMAKE_SKIP_BUILD_RPATH FALSE)
+SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
+SET(CMAKE_INSTALL_RPATH "/usr/lib/osp-server")
+SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
+
 ## Create Library
 ADD_EXECUTABLE (${this_target} ${${this_target}_SOURCE_FILES})
 
 TARGET_LINK_LIBRARIES(${this_target} -Xlinker --no-undefined -Xlinker --as-needed -pie)
 TARGET_LINK_LIBRARIES(${this_target} -Xlinker --version-script=${CMAKE_CURRENT_SOURCE_DIR}/system-service-export.ver)
 TARGET_LINK_LIBRARIES(${this_target} "-L/usr/lib/osp -losp-appfw -lchromium")
-
+TARGET_LINK_LIBRARIES(${this_target} "-lbundle" )
+TARGET_LINK_LIBRARIES(${this_target} "-ldlog" )
+TARGET_LINK_LIBRARIES(${this_target} "-lglib-2.0" )
+TARGET_LINK_LIBRARIES(${this_target} "-lmessage-port" )
+TARGET_LINK_LIBRARIES(${this_target} "-lsmack" )
+TARGET_LINK_LIBRARIES(${this_target} "-lpthread" )
+TARGET_LINK_LIBRARIES(${this_target} "-lcrypto" )
+TARGET_LINK_LIBRARIES(${this_target} "-lsoup-2.4" )
+TARGET_LINK_LIBRARIES(${this_target} "-L/usr/lib/osp-server -losp-appfw-server")
 
 ## Cory additional info
 INSTALL(TARGETS ${this_target} DESTINATION ../usr/apps/${APPID}/bin)
index 3a4b7b6..1bb2439 100644 (file)
@@ -34,10 +34,10 @@ namespace Tizen { namespace Io {
 class _ChannelService;
 class _ChannelServiceStub;
 
-class _MessagePortService;
-class _MessagePortStub;
 } }
 
+class _MessagePortService;
+class _MessagePortStub;
 
 /**
  * [ChannelService] ServiceApp must inherit from ServiceApp class
@@ -79,8 +79,8 @@ private:
        Tizen::Io::_ChannelService*     __pChannelService;
        Tizen::Io::_ChannelServiceStub* __pChannelServiceStub;
 
-       Tizen::Io::_MessagePortService* __pMessagePortService;
-       Tizen::Io::_MessagePortStub*    __pMessagePortStub;
+       _MessagePortService*    __pMessagePortService;
+       _MessagePortStub*       __pMessagePortStub;
 }; // ChannelService
 
 #endif // _CHANNEL_SERVICE_H_
diff --git a/inc/FIo_ChannelCAppStub.h b/inc/FIo_ChannelCAppStub.h
new file mode 100644 (file)
index 0000000..585c6ed
--- /dev/null
@@ -0,0 +1,128 @@
+//
+// Open Service Platform
+// Copyright (c) 2012 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+/**
+ * @file       FIo_ChannelCAppStub.h
+ * @brief      This is the header file for the _ChannelCAppStub class.
+ *
+ * This file contains the declarations of _ChannelCAppStub.
+ */
+
+#ifndef _FIO_INTERNAL_CHANNEL_CAPP_STUB_H_
+#define _FIO_INTERNAL_CHANNEL_CAPP_STUB_H_
+
+#include <string>
+#include <pthread.h>
+#include <map>
+#include <glib.h>
+
+#include <FOspConfig.h>
+#include <FBaseObject.h>
+#include <FBaseString.h>
+#include <FBaseResult.h>
+#include <FBaseColArrayList.h>
+#include <FIo_ChannelService.h>
+
+namespace Tizen { namespace Base { namespace Runtime
+{
+class _EventDispatcher;
+}}}
+
+namespace Tizen { namespace Io
+{
+
+class _IIpcServerEventListener;
+class _ChannelServiceStub;
+
+/**
+ * @class _ChannelCAppStub
+ * @brief This class provides methods to handle c-application request messages.
+ * @since 2.1
+ *
+ */
+class _OSP_EXPORT_ _ChannelCAppStub
+       : public Tizen::Base::Object
+{
+public:
+       /**
+        * This is the default constructor for this class.
+        * @since 2.1
+        */
+       _ChannelCAppStub(void);
+
+       /**
+        * This is the destructor for this class.
+        * @since 2.1
+        */
+       virtual ~_ChannelCAppStub(void);
+
+       result Construct(void);
+
+       void SetChannelService(_ChannelService& service);
+
+       static bool SendResponse(int requestId, void* pGIOChannel, const Tizen::Base::Collection::ArrayList& args);
+
+private:
+       _ChannelCAppStub(const _ChannelCAppStub& rhs);
+
+       _ChannelCAppStub& operator =(const _ChannelCAppStub& rhs);
+
+       static gboolean OnConnectionRequest(GIOChannel* source, GIOCondition condition, gpointer data);
+
+       static gboolean OnReadMessage(GIOChannel* source, GIOCondition condition, gpointer data);
+
+       gboolean HandleReceivedMessage(GIOChannel* source, GIOCondition condition, gpointer data);
+
+       _ChannelService* __pChannelService;
+
+       struct  _ClientInfo;
+
+       struct  _ChannelInfo
+       {
+               _ChannelInfo(void);
+               ~_ChannelInfo(void);
+
+               struct _ClientInfo* pClientInfo;
+               GIOChannel* pGIOChannel;
+               GSource* pGSource;
+               bool destroySource;
+       };
+
+       struct  _ClientInfo
+       {
+               _ClientInfo(void);
+               ~_ClientInfo(void);
+
+               int clientId;                              /**< the client id */
+               _ChannelCAppStub* pChannelStub;                    /**< the pointer to an _ChannelCAppStub */
+               std::vector <struct _ChannelInfo*> channels;   /**< the set of channels associated with a client */
+               Tizen::Base::String appId;
+               //Tizen::Base::String appExecutableName;
+       };
+
+       GMainContext* __pGMainContext;
+
+       GSource* __pConnectGSource;
+
+       std::map <int, _ClientInfo*> __clients;   // pid of client is used for key
+
+}; // _ChannelCAppStub
+
+}} // Tizen::Io
+
+#endif // _FIO_INTERNAL_CHANNEL_CAPP_STUB_H_
+
diff --git a/inc/FIo_ChannelService.h b/inc/FIo_ChannelService.h
new file mode 100644 (file)
index 0000000..d04cf30
--- /dev/null
@@ -0,0 +1,124 @@
+//
+// Open Service Platform
+// Copyright (c) 2012 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+/**
+ * @file       FIo_ChannelService.h
+ * @brief      This is the header file for the _ChannelService class.
+ *
+ * This file contains the declarations of _ChannelService.
+ */
+
+#ifndef _FIO_INTERNAL_CHANNEL_SERVICE_H_
+#define _FIO_INTERNAL_CHANNEL_SERVICE_H_
+
+#include <vector>
+
+#include <FBaseResult.h>
+#include <FBaseObject.h>
+#include <FBaseColIList.h>
+#include <FBaseColHashMapT.h>
+#include <FOspConfig.h>
+#include "FIo_IChannelService.h"
+#include "FIo_IChannelServiceEventListener.h"
+
+namespace IPC
+{
+class Message;
+}
+
+namespace Tizen { namespace Io
+{
+class _IChannelServiceStub;
+class _ChannelCAppStub;
+
+enum _ChannelType
+{
+       OSPAPP_CHANNEL = 0,
+       CAPP_CHANNEL,
+       WEBAPP_CHANNEL
+};
+
+class _OSP_EXPORT_ _ChannelService
+       : public Tizen::Base::Object
+       , public Tizen::Io::_IChannelService
+{
+public:
+       _ChannelService(void);
+
+       virtual ~_ChannelService(void);
+
+       virtual result Construct(_IChannelServiceStub& stub);
+
+       // _IChannelService
+       virtual result RegisterChannel(const Tizen::Base::String& channelId, const _IChannelServiceEventListener& listener);
+       virtual result UnregisterChannel(const Tizen::Base::String& channelId);
+
+       virtual result SendRequest(const Tizen::Base::String& src, const Tizen::Base::String& dest, const Tizen::Base::Collection::ArrayList& args, int messageId);
+       virtual result SendNullRequest(const Tizen::Base::String& src, const Tizen::Base::String& dest, int messageId);
+
+       virtual result SendResponse(const Tizen::Base::String& src, const Tizen::Base::String& dest, const Tizen::Base::Collection::ArrayList& args, int messageId);
+       virtual result SendNullResponse(const Tizen::Base::String& src, const Tizen::Base::String& dest, int messageId);
+
+
+       bool IsChannelRegistered(const Tizen::Base::String& channelId);
+
+       result RegisterChannel(const Tizen::Base::String& channelId, int clientId, unsigned int type = OSPAPP_CHANNEL);
+
+       result RegisterChannel(const Tizen::Base::String& channelId, int clientId, void* pGIOChannel);
+
+       result UnregisterChannel(int clientId);
+
+private:
+
+       struct _ChannelInfo
+       {
+               Tizen::Base::String channelId;
+               int clientId;
+               void* pGIOChannel;
+               unsigned int type;
+       };
+
+       class _StringHashProvider
+               : public Tizen::Base::Collection::IHashCodeProviderT<Tizen::Base::String>
+       {
+       public:
+               virtual int GetHashCode(const Tizen::Base::String& value) const
+               {
+                       return value.GetHashCode();
+               }
+       };
+
+       class _StringComparer
+               : public Tizen::Base::Collection::IComparerT<Tizen::Base::String>
+       {
+       public:
+               virtual result Compare(const Tizen::Base::String& string1, const Tizen::Base::String& string2, int& cmp) const
+               {
+                       cmp = string1.CompareTo(string2);
+                       return E_SUCCESS;
+               }
+       };
+private:
+       _IChannelServiceStub* __pIChannelServiceStub;
+       Tizen::Base::Collection::HashMapT <Tizen::Base::String, _ChannelInfo*> __channels;
+
+}; // _ChannelService
+
+
+} } // Tizen::Io
+
+#endif // _FIO_INTERNAL_CHANNEL_SERVICE_STUB_H_
diff --git a/inc/FIo_ChannelServiceStub.h b/inc/FIo_ChannelServiceStub.h
new file mode 100644 (file)
index 0000000..7dd1339
--- /dev/null
@@ -0,0 +1,128 @@
+//
+// Open Service Platform
+// Copyright (c) 2012 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+/**
+ * @file       FIo_ChannelServiceStub.h
+ * @brief      This is the header file for the _ChannelServiceStub class.
+ *
+ * This file contains the declarations of _ChannelServiceStub.
+ */
+
+
+#ifndef _FIO_INTERNAL_CHANNEL_SERVICE_STUB_H_
+#define _FIO_INTERNAL_CHANNEL_SERVICE_STUB_H_
+
+#include <FOspConfig.h>
+#include <FBaseResult.h>
+#include <FBaseObject.h>
+#include <FBaseColArrayList.h>
+#include <FBaseRt_ITask.h>
+#include "FIo_IIpcServerEventListener.h"
+#include "FIo_IChannelServiceStub.h"
+
+namespace IPC
+{
+class Message;
+}
+
+namespace Tizen { namespace Io
+{
+
+class _IpcServer;
+class _ChannelService;
+
+class _OSP_EXPORT_ _ChannelServiceStub
+       : public _IIpcServerEventListener
+       , public _IChannelServiceStub
+       , public Tizen::Base::Object
+{
+public:
+       _ChannelServiceStub(void);
+
+       virtual ~_ChannelServiceStub(void);
+
+       virtual result Construct(void);
+
+       // _IChannelServiceStub
+       virtual result SendRequest(int clientId, const Tizen::Base::String& src,
+                                                          const Tizen::Base::String& dest,
+                                                          const Tizen::Base::Collection::ArrayList& args,
+                                                          int requestId);
+
+       virtual result SendNullRequest(int clientId, const Tizen::Base::String& src,
+                                                          const Tizen::Base::String& dest,
+                                                          int requestId);
+
+       virtual result SendResponse(int clientId, const Tizen::Base::String& src,
+                                                               const Tizen::Base::String& dest,
+                                                               const Tizen::Base::Collection::ArrayList& args,
+                                                               int requestId);
+
+       virtual result SendNullResponse(int clientId, const Tizen::Base::String& src,
+                                                               const Tizen::Base::String& dest,
+                                                               int requestId);
+
+       virtual void SetChannelService(_ChannelService& service);
+
+
+private:
+       bool OnRegisterChannelMessage(const Tizen::Base::String& appId, int* pResult);
+
+       bool OnSendRequestMessage(const Tizen::Base::String& src,
+                                                         const Tizen::Base::String& dest,
+                                                         const Tizen::Base::Collection::ArrayList& args,
+                                                         int requestId,
+                                                         int* pResult);
+
+       bool OnSendNullRequestMessage(const Tizen::Base::String& src,
+                                                         const Tizen::Base::String& dest,
+                                                         int requestId,
+                                                         int* pResult);
+
+       bool OnSendResponseMessage(const Tizen::Base::String& src,
+                                                          const Tizen::Base::String& dest,
+                                                          const Tizen::Base::Collection::ArrayList& args,
+                                                          int requestId,
+                                                          int* pResult);
+
+       bool OnSendNullResponseMessage(const Tizen::Base::String& src,
+                                                          const Tizen::Base::String& dest,
+                                                          int requestId,
+                                                          int* pResult);
+
+       virtual void OnIpcRequestReceived(_IpcServer& server, const IPC::Message& message);
+
+       virtual void OnIpcServerStarted(const _IpcServer& server);
+
+       virtual void OnIpcServerStopped(const _IpcServer& server);
+
+       virtual void OnIpcClientConnected(const _IpcServer& server, int clientId);
+
+       virtual void OnIpcClientDisconnected(const _IpcServer& server, int clientId);
+
+       _ChannelServiceStub(const _ChannelServiceStub& value);
+       _ChannelServiceStub& operator = (const _ChannelServiceStub& value);
+private:
+       _IpcServer* __pIpcServer;
+       _ChannelService* __pChannelService;
+
+}; // _ChannelServiceStub
+
+} } // Tizen::Io
+
+#endif // _FIO_INTERNAL_CHANNEL_SERVICE_STUB_H_
+
diff --git a/inc/FIo_ChannelWebAppStub.h b/inc/FIo_ChannelWebAppStub.h
new file mode 100644 (file)
index 0000000..b882bf9
--- /dev/null
@@ -0,0 +1,223 @@
+//
+// Open Service Platform
+// Copyright (c) 2012 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+/**
+ * @file       FIo_ChannelWebAppStub.h
+ * @brief      This is the header file for the _ChannelWebAppStub class.
+ *
+ * This file contains the declarations of _ChannelWebAppStub.
+ */
+
+#ifndef _FIO_INTERNAL_CHANNEL_WEBAPP_STUB_H_
+#define _FIO_INTERNAL_CHANNEL_WEBAPP_STUB_H_
+
+#include <string>
+#include <pthread.h>
+#include <map>
+#include <glib.h>
+#include <libsoup/soup.h>
+
+#include <FOspConfig.h>
+#include <FBaseObject.h>
+#include <FBaseString.h>
+#include <FBaseResult.h>
+#include <FBaseColArrayList.h>
+#include <FBaseColHashMap.h>
+#include <FAppTypes.h>
+#include <FIo_ChannelService.h>
+
+namespace Tizen { namespace Base { namespace Runtime
+{
+class _EventDispatcher;
+}}}
+
+namespace Tizen { namespace Io
+{
+
+enum WebSocketType
+{
+       WS_NONE,
+       WS_HYBI00,
+       WS_HYBI10
+};
+
+class _IIpcServerEventListener;
+class _ChannelServiceStub;
+
+/**
+ * @class _ChannelWebAppStub
+ * @brief This class provides methods to handle web-application request messages.
+ * @since 2.1
+ *
+ */
+class _OSP_EXPORT_ _ChannelWebAppStub
+       : public Tizen::Base::Object
+{
+public:
+       /**
+        * This is the default constructor for this class.
+        * @since 2.1
+        */
+       _ChannelWebAppStub(void);
+
+       /**
+        * This is the destructor for this class.
+        * @since 2.1
+        */
+       virtual ~_ChannelWebAppStub(void);
+
+       result Construct(void);
+
+       void SetChannelService(_ChannelService& service);
+
+       static bool SendResponse(int clientId, const Tizen::Base::Collection::ArrayList& args);
+
+private:
+       _ChannelWebAppStub(const _ChannelWebAppStub& rhs);
+
+       _ChannelWebAppStub& operator =(const _ChannelWebAppStub& rhs);
+
+       static gboolean OnConnectionRequest(GIOChannel* source, GIOCondition condition, gpointer data);
+
+       static gboolean OnReadMessage(GIOChannel* source, GIOCondition condition, gpointer data);
+
+       gboolean HandleReceivedMessage(GIOChannel* source, GIOCondition condition, gpointer data);
+
+       static std::string CreateResponseHeader(int appSocket, SoupMessageHeaders *header, const std::string& response);
+
+       static WebSocketType VerifyHttpHeaderType(std::string header, int headerLength);
+       static std::string MakeHybi00Response(uint32_t first, uint32_t second, unsigned char* third);
+       static std::string MakeHybi10Response(std::string& secureAccept);
+
+       static bool AppendChallengeNumber(uint32_t number, unsigned char *response);
+       static unsigned int ExtractChallengeNumber(const char* keyString);
+       static char* EncodeBase64(unsigned char *string, int len);
+
+
+//     struct  _ClientInfo;
+//
+//     struct  _ChannelInfo
+//     {
+//             _ChannelInfo(void);
+//             ~_ChannelInfo(void);
+//
+//             struct _ClientInfo* pClientInfo;
+//             GIOChannel* pGIOChannel;
+//             GSource* pGSource;
+//             bool destroySource;
+//     };
+//
+//     struct  _ClientInfo
+//     {
+//             _ClientInfo(void);
+//             ~_ClientInfo(void);
+//
+//             int clientId;                              // the client id
+//             _ChannelWebAppStub* pChannelStub;                   // the pointer to an _ChannelWebAppStub
+//             //GIOChannel* pReverseChannel;               // the channel for sending reverse message
+//             std::vector <struct _ChannelInfo*> channels;   // the set of channels associated with a client
+//             //Tizen::Base::String appId;
+//             //Tizen::Base::String appExecutableName;
+//     };
+
+       class _ClientInfo;
+
+       class _ChannelInfo
+       {
+       public:
+               _ChannelInfo(void);
+               ~_ChannelInfo(void);
+
+               _ClientInfo* pClientInfo;
+
+               Tizen::App::AppId destAppId;
+
+               GIOChannel* pGIOChannel;
+               GSource* pGSource;
+               bool destroySource;
+       };
+
+       class _ClientInfo
+               : public Tizen::Base::Object
+       {
+       public:
+               _ClientInfo(void);
+               ~_ClientInfo(void);
+
+               Tizen::App::AppId srcAppId;
+
+               //int clientId;
+               Tizen::Base::String key; // key = srcAppId + srcAppExecName
+               _ChannelWebAppStub* pChannelStub;
+               std::vector <struct _ChannelInfo*> channels;   /**< the set of channels associated with a client */
+       };
+
+       class _WebSocketMessage
+       {
+               public:
+                       _WebSocketMessage(void);
+                       ~_WebSocketMessage(void);
+
+
+                       typedef union
+                       {
+                               struct
+                               {
+                                       unsigned int opcode : 4;
+                                       unsigned int rsv3 : 1;
+                                       unsigned int rsv2 : 1;
+                                       unsigned int rsv1 : 1;
+                                       unsigned int fin : 1;
+                                       unsigned int payloadLen : 7;
+                                       unsigned int masked : 1;
+                               } factors;
+                               uint16_t header;
+                       } MiniHeader;
+
+                       int ParseHeader(uint8_t* header, int messageLen);
+                       int ParsePayload(uint8_t* payload, int messageLen);
+                       void ConsoleMessage() const;
+                       static size_t CreateMessage(std::string& payload, std::string& message);
+
+                       MiniHeader m_header;
+                       uint8_t m_payloadOffset;
+                       uint8_t m_maskingKey[4];
+                       uint64_t m_payloadLen;
+                       bool m_headerParsed;
+                       uint8_t* m_payload;
+
+               private:
+                       _WebSocketMessage(_WebSocketMessage& webSocketMessage);
+
+                       _WebSocketMessage& operator =(const _WebSocketMessage& webSocketMessage);
+
+       };
+
+       _ChannelService* __pChannelService;
+
+       GMainContext* __pGMainContext;
+       GSource* __pServerGSource;
+       GSource* __pClientGSource;
+
+       Tizen::Base::Collection::HashMap* __pClients;
+
+}; // _ChannelWebAppStub
+
+}} // Tizen::Io
+
+#endif // _FIO_INTERNAL_CHANNEL_WEBAPP_STUB_H_
+
index a9a3a58..0dfab26 100644 (file)
@@ -25,6 +25,8 @@
 #ifndef _FIO_INTERNAL_MESSAGE_PORT_SERVICE_H_
 #define _FIO_INTERNAL_MESSAGE_PORT_SERVICE_H_
 
+#include <message-port-data-types.h>
+
 #include <FBaseResult.h>
 #include <FBaseString.h>
 #include <FBaseColHashMap.h>
@@ -36,9 +38,6 @@ namespace IPC
 class Message;
 }
 
-namespace Tizen { namespace Io
-{
-
 class _MessagePortStub;
 
 class _MessagePortService
@@ -50,32 +49,16 @@ public:
 
        virtual result Construct(_MessagePortStub& stub);
 
-       virtual result RegisterMessagePort(const Tizen::Base::String& appId,
-                                                                       const Tizen::Base::String& port,
-                                                                  int clientId,
-                                                                  bool isTrusted);
+       virtual int RegisterMessagePort(int clientId, const BundleBuffer& buffer);
 
-       virtual result RequestRemotePort(const Tizen::App::AppId& remoteAppId,
-                                                                       const Tizen::Base::String& remotePort,
-                                                                  bool isTrusted);
+       virtual int CheckRemotePort(const BundleBuffer& buffer);
 
        result UnregisterMessagePort(int clientId);
 
-       virtual result SendMessage(const Tizen::Base::String& dest,
-                                                       const Tizen::Base::String& destPort,
-                                                       bool isTrusted,
-                                                       const Tizen::Base::Collection::HashMap* pMap);
-
-       virtual result SendMessage(const Tizen::Base::String& src,
-                                                       const Tizen::Base::String& srcPort,
-                                                       bool isTrustedSrc,
-                                                       const Tizen::Base::String& dest,
-                                                       const Tizen::Base::String& destPort,
-                                                       bool isTrustedDest,
-                                                       const Tizen::Base::Collection::HashMap* pMap);
+       virtual result SendMessage(const BundleBuffer& buffer);
 
 private:
-       Tizen::Base::String GetKey(const Tizen::Base::String& appId, const Tizen::Base::String& port) const;
+       Tizen::Base::String GetKey(const BundleBuffer& buffer, bool local = true) const;
 
        class _StringHashProvider
                : public Tizen::Base::Collection::IHashCodeProviderT<Tizen::Base::String>
@@ -105,6 +88,4 @@ private:
        Tizen::Base::Collection::HashMapT <Tizen::Base::String, int>* __pTrustedPorts;
 }; // _MessagePortService
 
-} } // Tizen::Io
-
 #endif // _FIO_INTERNAL_MESSAGE_PORT_SERVICE_H_
index e56693d..5510bc7 100644 (file)
 #ifndef _FIO_INTERNAL_MESSAGE_PORT_STUB_H_
 #define _FIO_INTERNAL_MESSAGE_PORT_STUB_H_
 
+#include <message-port-data-types.h>
+
 #include <FBaseResult.h>
 #include <FBaseObject.h>
 #include <FBaseColArrayList.h>
 #include <FBaseColHashMap.h>
 #include <FAppTypes.h>
 
-#include <FIo_IIpcServerEventListener.h>
+#include "IpcServer.h"
+#include "IIpcServerEventListener.h"
 
 namespace IPC
 {
 class Message;
 }
 
-namespace Tizen { namespace Io
-{
-class _IpcServer;
-
 class _MessagePortService;
 
 class _MessagePortStub
-       : public Tizen::Io::_IIpcServerEventListener
+       : public IIpcServerEventListener
 {
 public:
        _MessagePortStub(void);
@@ -54,69 +53,37 @@ public:
 
        virtual result Construct(void);
 
-       result SendMessage(int clientId,
-                                               const Tizen::Base::String& destPort,
-                                               bool isTrusted,
-                                               const Tizen::Base::Collection::HashMap* pMap);
-
-       result SendMessage(int clientId,
-                                               const Tizen::Base::String& destPort,
-                                               bool isTrustedDest,
-                                               const Tizen::Base::String& src,
-                                               const Tizen::Base::String& srcPort,
-                                               bool isTrustedSrc,
-                                               const Tizen::Base::Collection::HashMap* pMap);
+       result SendMessage(int clientId, const BundleBuffer& buffer);
 
        void SetMessagePortService(_MessagePortService& service);
 
-
 private:
-       bool OnRegisterMessagePort(const Tizen::Base::String& appId, const Tizen::Base::String& port, bool isTrusted,  int* pResult);
-
-       bool OnRequestRemotePort(const Tizen::App::AppId& remoteAppId, const Tizen::Base::String& remotePort, bool isTrusted, int* pResult);
-
-       bool OnSendMessage(const Tizen::Base::String& dest,
-                                       const Tizen::Base::String& destPort,
-                                       bool isTrusted,
-                                       const Tizen::Base::Collection::HashMap& map,
-                                       int* pResult);
+       bool OnRegisterMessagePort(const BundleBuffer& buffer, int* pResult);
 
-       bool OnSendBidirMessage(const Tizen::Base::String& src,
-                                                       const Tizen::Base::String& srcPort,
-                                                       bool isTrusted,
-                                                       const Tizen::Base::String& dest,
-                                                       const Tizen::Base::String& destPort,
-                                                       const Tizen::Base::Collection::HashMap& map,
-                                                       int* pResult);
+       bool OnCheckRemotePort(const BundleBuffer& buffer, int* pResult);
 
-       bool OnSendTrustedBidirMessage(const Tizen::Base::String& src,
-                                                       const Tizen::Base::String& srcPort,
-                                                       bool isTrusted,
-                                                       const Tizen::Base::String& dest,
-                                                       const Tizen::Base::String& destPort,
-                                                       const Tizen::Base::Collection::HashMap& map,
-                                                       int* pResult);
+       bool OnSendMessage(const BundleBuffer& buffer, int* pResult);
 
-       virtual void OnIpcRequestReceived(Tizen::Io::_IpcServer& server, const IPC::Message& message);
+       virtual void OnIpcRequestReceived(IpcServer& server, const IPC::Message& message);
 
-       virtual void OnIpcServerStarted(const Tizen::Io::_IpcServer& server);
+       virtual void OnIpcServerStarted(const IpcServer& server);
 
-       virtual void OnIpcServerStopped(const Tizen::Io::_IpcServer& server);
+       virtual void OnIpcServerStopped(const IpcServer& server);
 
-       virtual void OnIpcClientConnected(const Tizen::Io::_IpcServer& server, int clientId);
+       virtual void OnIpcClientConnected(const IpcServer& server, int clientId);
 
-       virtual void OnIpcClientDisconnected(const Tizen::Io::_IpcServer& server, int clientId);
+       virtual void OnIpcClientDisconnected(const IpcServer& server, int clientId);
 
        _MessagePortStub(const _MessagePortStub& value);
        _MessagePortStub& operator = (const _MessagePortStub& value);
 
 private:
-       Tizen::Io::_IpcServer* __pIpcServer;
+       IpcServer* __pIpcServer;
        _MessagePortService* __pService;
 
 }; // _MessagePortStub
 
-} } // Tizen::Io
+//} } // Tizen::Io
 
 #endif // _FIO_INTERNAL_MESSAGE_PORT_STUB_H_
 
diff --git a/inc/IIpcServerEventListener.h b/inc/IIpcServerEventListener.h
new file mode 100644 (file)
index 0000000..eba3a32
--- /dev/null
@@ -0,0 +1,127 @@
+//
+// Open Service Platform
+// Copyright (c) 2012 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+/**
+ * @file       FIo_IIpcServerEventListener.h
+ * @brief      This is the header file for the _IIpcServerEventListener class.
+ *
+ * This file contains the declarations of _IIpcServerEventListener.
+ */
+
+//#include <FOspConfig.h>
+//#include <FBaseRtIEventListener.h>
+
+#ifndef _IIPC_SERVER_EVENT_LISTENER_H_
+#define _IIPC_SERVER_EVENT_LISTENER_H_
+
+namespace IPC { class Message; }
+
+//namespace Tizen { namespace Io
+//{
+
+class IpcServer;
+/**
+ * @interface IIpcServerEventListener
+ * @brief     This interface provides listener method for the request event from an IPC client.
+ * since      3.0
+ */
+class IIpcServerEventListener
+       //: virtual Tizen::Base::Runtime::IEventListener
+{
+public:
+       /**
+        * This is the destructor for this class.
+        *
+        * @since 2.1
+        */
+       virtual ~IIpcServerEventListener(void) {}
+
+       /**
+        * Called when an IPC server started.
+        *
+        * @since 2.1
+        * @param[in] server The IPC server
+        */
+       virtual void OnIpcServerStarted(const IpcServer& server) = 0;
+
+       /**
+        * Called when an IPC server stopped.
+        *
+        * @since 2.1
+        * @param[in] server The IPC server
+        */
+       virtual void OnIpcServerStopped(const IpcServer& server) = 0;
+
+       /**
+        * Called when an IPC client connected.
+        *
+        * @since 2.1
+        * @param[in] server The IPC server
+        */
+       virtual void OnIpcClientConnected(const IpcServer& server, int clientId) = 0;
+
+       /**
+        * Called when an IPC client disconnected.
+        *
+        * @since 2.1
+        * @param[in] server The IPC server
+        * @param[in] clientId The id of the connected IPC client
+        */
+       virtual void OnIpcClientDisconnected(const IpcServer& server, int clientId) = 0;
+
+       /**
+        * Called when an IPC request message received.
+        *
+        * @since 2.1
+        * @code
+        *
+        * bool
+        * CalculatorStub::OnSumRequested(int a, int b, int* pC)
+        * {
+        *    *pC = a + b;
+        *    return true;
+        * }
+        *
+        * bool
+        * CalculatorStub::OnMultiplyRequested(int a, int b, int* pC)
+        * {
+        *    *pC = a * b;
+        *    return true;
+        * }
+        *
+        * bool
+        * CalculatorStub::OnIpcRequestReceived(IpcServer& server, const IPC::Message& message)
+        * {
+        *    IPC_BEGIN_MESSAGE_MAP(CalculatorStub, message)
+        *         IPC_MESSAGE_HANDLER(My_sum, OnSumRequested, &server)
+        *         IPC_MESSAGE_HANDLER(My_mul, OnMultiplyRequested, &server)
+        *    IPC_END_MESSAGE_MAP()
+        *
+        *    return true;
+        * }
+        *
+        * @endcode
+        * @param[in] server    The IPC server
+        * @param[in] message   The received message
+        */
+       virtual void OnIpcRequestReceived(IpcServer& server, const IPC::Message& message) = 0;
+}; // _IIpcServerEventListener
+
+
+//} } // Tizen::Io
+
+#endif //_IIPC_SERVER_EVENT_LISTENER_H_
diff --git a/inc/IpcServer.h b/inc/IpcServer.h
new file mode 100644 (file)
index 0000000..e40b335
--- /dev/null
@@ -0,0 +1,226 @@
+//
+// Open Service Platform
+// Copyright (c) 2012 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+/**
+ * @file       FIo_IpcServer.h
+ * @brief      This is the header file for the IpcServer class.
+ *
+ * This file contains the declarations of IpcServer.
+ */
+
+#ifndef _IPC_SERVER_H_
+#define _IPC_SERVER_H_
+
+#include <string>
+#include <pthread.h>
+#include <map>
+#include <glib.h>
+
+#include <ipc/ipc_message_macros.h>
+#include <ipc/ipc_message_utils.h>
+
+#include <FBaseResult.h>
+#include <FBaseObject.h>
+#include <FBaseString.h>
+#include <FAppTypes.h>
+
+#include "IIpcServerEventListener.h"
+
+namespace Tizen { namespace Base { namespace Runtime
+{
+class _EventDispatcher;
+}}}
+
+/**
+ * @class IpcServer
+ * @brief This class provides methods to handle IPC request messages.
+ *
+ */
+class _OSP_EXPORT_ IpcServer
+       : public Tizen::Base::Object
+{
+public:
+       IpcServer(void);
+
+       virtual ~IpcServer(void);
+
+       /**
+        * Constructs the instance of this class and starts the IPC server.
+        *
+        * @return An error code
+        * @param[in] name                      The name of IPC server
+        * @param[in] listener          The listener for IPC server
+        * @param[in] runOnCallerThread Set to @c true, if the server runs on the caller thread
+        *                                      @c false, if the server runs on its own thread.
+        * @exception E_SUCCESS         The method was successful.
+        * @exception E_OUT_OF_MEMORY   Insufficient memory.
+        * @exception E_SYSTEM          Occurs when runOnCallerThread is set to true where the caller thread is worker thread.
+        */
+       result Construct(const Tizen::Base::String& name, const IIpcServerEventListener& listener, bool runOnCallerThread = true);
+
+       /**
+        * Returns the name of the IPC server.
+        *
+        * @return The name of the IPC server.
+        */
+       Tizen::Base::String GetName(void) const;
+
+       /**
+        * Returns the id the of the client which sent a request message.
+        *
+        * @return The id of the IPC client.
+        * @remark This can be called only in a message handler.
+        */
+       int GetClientId(void) const;
+
+       /**
+        * Returns the process id of the client which sent a request message.
+        *
+        * @return The process id of the IPC client.
+        * @remark This can be called only in a message handler.
+        */
+       int GetClientProcessId(void) const;
+
+       /**
+        * Returns the package id of the client which sent a request message.
+        *
+        * @return The package id of the IPC client.
+        * @remark This can be called only in a message handler.
+        */
+       Tizen::Base::String GetClientAppId(void) const;
+
+       /**
+        * Returns the executable name of the client which sent a request message.
+        *
+        * @return The executable name of the IPC client.
+        * @remark This can be called only in a message handler.
+        */
+       Tizen::Base::String GetClientAppExecutableName(void) const;
+
+       /**
+        * Returns the application id of the client which sent a request message.
+        *
+        * @return The application id of the IPC client.
+        * @remark This can be called only in a message handler.
+        */
+       Tizen::App::AppId GetClientApplicationId(void) const;
+
+       /**
+        * Stops the IPC server.
+        *
+        * @return An error code
+        * @exception E_SUCCESS         The method was successful.
+        * @exception E_INVALID_STATE   The IPC server has not been started.
+        */
+       result Stop(void);
+
+       /**
+        * Sends a message to an IPC client.
+        *
+        * @return An error code
+        * @param[in] clientId      The id of the IPC client
+        * @param[in] message   The message to send
+        * @exception E_SUCCESS The method was successful.
+        * @exception E_INVALID_ARG             The message is synchronous.
+        * @exception E_INVALID_OPERATION       The client didn't set a listener.
+        * @exception E_OUT_OF_MEMORY   Insufficient memory.
+        * @exception E_SYSTEM          A system error occurred.
+        *
+        * @remark Only an asychronous message can be sent to an IPC client.
+        */
+       result SendResponse(int clientId, const IPC::Message& message);
+
+       result Start(void);
+
+       result SendResponse(int clientId, IPC::Message* pMessage);
+
+       bool Send(IPC::Message* msg);
+
+private:
+       IpcServer(const IpcServer& value);
+
+       IpcServer& operator =(const IpcServer& value);
+
+       static void* ThreadProc(void* pParam);
+
+       void Run(void* pParam);
+
+       static gboolean OnConnectionRequest(GIOChannel* source, GIOCondition condition, gpointer data);
+
+       static gboolean OnReadMessage(GIOChannel* source, GIOCondition condition, gpointer data);
+
+       gboolean HandleReceivedMessage(GIOChannel* source, GIOCondition condition, gpointer data);
+
+       static const int __MAX_MESSAGE_BUFFER_SIZE = 1024;
+
+       struct  _ClientInfo;
+
+       /**
+        *      @struct __ChannelInfo
+        *      @brief  This struct represent a channel.
+        */
+       struct  _ChannelInfo
+       {
+               _ChannelInfo(void);
+               ~_ChannelInfo(void);
+
+               struct _ClientInfo* pClientInfo;
+               GIOChannel* pGIOChannel;
+               GSource* pGSource;
+               bool destroySource;
+       };
+
+       /**
+        *      @struct __ClientInfo
+        *      @brief  This struct represent a client connected to this server.
+        */
+       struct  _ClientInfo
+       {
+               _ClientInfo(void);
+               ~_ClientInfo(void);
+
+               int clientId;                              /**< the client id */
+               IpcServer* pIpcServer;                    /**< the pointer to an _ IpcServer */
+               GIOChannel* pReverseChannel;               /**< the channel for sending reverse message */
+               std::vector <struct _ChannelInfo*> channels;   /**< the set of channels associated with a client */
+               Tizen::Base::String appId;
+       };
+
+       Tizen::Base::String __name;
+       bool __runOnCallerThread;
+       Tizen::Base::Runtime::_EventDispatcher* __pEventDispatcher;
+       IIpcServerEventListener* __pListener;
+
+       pthread_t __handlerThread;
+       GMainContext* __pHandlerGMainContext;
+       GMainLoop* __pHandlerGMainLoop;
+
+       // handling connection
+       GSource* __pConnectGSource;
+
+       // handling received message
+       char __messageBuffer[__MAX_MESSAGE_BUFFER_SIZE];
+       std::string __pending;
+
+       // current message handling context
+       GIOChannel* __pCurrentChannel;
+       _ClientInfo* __pCurrentClientInfo;
+
+       std::map <int, _ClientInfo*> __clients;   // pid of client is used for key
+}; // IpcServer
+
+#endif // _IPC_SERVER_H_
index de93d5a..bfd2e78 100644 (file)
@@ -17,7 +17,7 @@
         <ApiVersion>2.1</ApiVersion>
         <Secret>9C645DDBA19C71BAD1204DA4DAA7A0B9</Secret>
         <Privileges/>
-        <ServiceApp Default="True" ExecutableName="osp-channel-service">
+        <ServiceApp SystemService="True" Default="True" ExecutableName="osp-channel-service">
             <Names>
                 <Name Locale="eng-GB">osp-channel-service</Name>
             </Names>
index 051ee21..6896c16 100644 (file)
@@ -1,12 +1,11 @@
 <manifest>
        <define>
-               <domain name="osp-channel-service"/>
+               <domain name="cp7ipabg4k"/>
        </define>
        <request>
-               <domain name="osp-channel-service"/>
+               <domain name="cp7ipabg4k"/>
        </request>
        <assign>
-               <filesystem path="/usr/apps/cp7ipabg4k/bin/osp-channel-service.sh" label="osp-channel-service" exec_label="osp-channel-service"/>
                <filesystem path="/usr/share/license/osp-channel-service" label="_"/>
        </assign>
-</manifest>
\ No newline at end of file
+</manifest>
index 8b6f0c2..03fda6b 100755 (executable)
@@ -1,14 +1,21 @@
 Name:          osp-channel-service
 Summary:       osp channel service
-Version:       1.2.0.0
-Release:       1
+Version:       1.2.1.0
+Release:       2
 Group:         TO_BE/FILLED_IN
 License:    Apache License, Version 2.0
 Source0:       %{name}-%{version}.tar.gz
 BuildRequires:  cmake
 BuildRequires: pkgconfig(glib-2.0)
-BuildRequires:  pkgconfig(osp-appfw)
+BuildRequires: pkgconfig(osp-appfw)
+BuildRequires: pkgconfig(bundle)
+BuildRequires: pkgconfig(dlog)
 BuildRequires: pkgconfig(chromium)
+BuildRequires: pkgconfig(libsoup-2.4)
+BuildRequires: pkgconfig(libssl)
+BuildRequires: pkgconfig(libsmack)
+BuildRequires: pkgconfig(message-port)
+BuildRequires: pkgconfig(openssl)
 BuildRequires:  osp-appfw-internal-devel
 
 # runtime requires
@@ -47,7 +54,6 @@ cp %{_builddir}/%{name}-%{version}/LICENSE.APLv2  %{buildroot}/usr/share/license
 /bin/rm -fr /opt/apps/cp7ipabg4k
 
 /usr/etc/package-manager/backend/tpk -i /usr/apps/cp7ipabg4k
-cp -f %{_libdir}/osp/osp-system-service-loader /usr/apps/cp7ipabg4k/bin/osp-channel-service
 if [ -f /usr/lib/rpm-plugins/msm.so ]
 then
        chsmack -a osp-channel-service /usr/apps/cp7ipabg4k/bin/osp-channel-service
diff --git a/src/FIo_ChannelCAppStub.cpp b/src/FIo_ChannelCAppStub.cpp
new file mode 100644 (file)
index 0000000..9ac1990
--- /dev/null
@@ -0,0 +1,558 @@
+//
+// Open Service Platform
+// Copyright (c) 2012 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+/**
+ * @file       FIo_ChannelCAppStub.cpp
+ * @brief      This is the implementation file for the  _ChannelCAppStub class.
+ *
+ */
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <cerrno>
+#include <iostream>
+
+#include <unique_ptr.h>
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <errno.h>
+
+#include <FBase_StringConverter.h>
+#include <FBaseDataType.h>
+#include <FBaseLong.h>
+#include <FBaseColArrayList.h>
+
+#include <FBaseRt_EventDispatcher.h>
+#include <FBaseSysLog.h>
+#include <FBaseUtilStringTokenizer.h>
+#include <FIo_ChannelServiceStub.h>
+#include <FApp_AppInfo.h>
+
+#include "FIo_ChannelCAppStub.h"
+
+#define MAX_BUFFER_LENGTH 4096
+
+static const int TOKEN_LENGTH = 7;
+static const int CAPP_PADDING_LENGTH = 7;
+
+using namespace std;
+
+using namespace Tizen::Base;
+using namespace Tizen::Base::Collection;
+using namespace Tizen::Base::Runtime;
+using namespace Tizen::Base::Utility;
+using namespace Tizen::Io;
+using namespace Tizen::App;
+
+using namespace std;
+
+namespace Tizen { namespace Io
+{
+
+_ChannelCAppStub::_ChannelCAppStub(void)
+       :__pChannelService(null)
+       , __pGMainContext(null)
+       , __pConnectGSource(null)
+{
+}
+
+_ChannelCAppStub::~_ChannelCAppStub(void)
+{
+       if (__pConnectGSource != null)
+       {
+               g_source_destroy(__pConnectGSource);
+               g_source_unref(__pConnectGSource);
+               __pConnectGSource = null;
+       }
+       __clients.clear();
+}
+
+_ChannelCAppStub::_ChannelInfo::_ChannelInfo(void)
+       : pClientInfo(null)
+       , pGIOChannel(null)
+       , pGSource(null)
+       , destroySource(true)
+{
+
+}
+_ChannelCAppStub::_ChannelInfo::~_ChannelInfo(void)
+{
+       if (pGIOChannel != null)
+       {
+               g_io_channel_unref(pGIOChannel);
+       }
+
+       if (pGSource != null)
+       {
+               if (destroySource)
+               {
+                       g_source_destroy(pGSource);
+               }
+
+               g_source_unref(pGSource);
+       }
+}
+
+_ChannelCAppStub::_ClientInfo::_ClientInfo(void)
+       : clientId(-1)
+       , pChannelStub(null)
+{
+
+}
+
+_ChannelCAppStub::_ClientInfo::~_ClientInfo(void)
+{
+       channels.clear();
+}
+
+result
+_ChannelCAppStub::Construct(void)
+{
+       GSource* pGSource = null;
+       GIOChannel* pGIOChannel = null;
+       const char* pSocketName = "/tmp/osp.io.socketserver.channelmanager\0";
+       size_t socketNameLength = 0;
+       struct sockaddr_un serverAddress;
+       int serverSocket = -1;
+       socklen_t serverLen = 0;
+       int ret = 0;
+       result r = E_SUCCESS;
+
+       socketNameLength = strlen(pSocketName) + 1;
+       SysTryReturnResult(NID_IO, socketNameLength < 108, E_SYSTEM,
+                       "Server name is too long.");
+
+       __pGMainContext = g_main_context_get_thread_default(); //get own gmain context except default thread
+       if (__pGMainContext == null)
+       {
+               __pGMainContext = g_main_context_default(); //get gmain context from me (default)
+               SysTryReturnResult(NID_IO, __pGMainContext != null, E_SYSTEM,
+                               "Failed to get glib context.");
+       }
+
+       ret = unlink(pSocketName);
+       SysTryLog(NID_IO, ret == 0, "Unlinking a socket %s has failed.. but it is not a problem.", pSocketName);
+
+       serverSocket = socket(AF_UNIX, SOCK_STREAM, 0);
+       SysTryReturnResult(NID_IO, serverSocket != -1, E_SYSTEM,
+                       "Failed to create a socket.");
+
+       bzero(&serverAddress, sizeof(serverAddress));
+       serverAddress.sun_family = AF_UNIX;
+       strncpy(serverAddress.sun_path, pSocketName, socketNameLength);
+       serverLen = sizeof(serverAddress);
+
+       ret = bind(serverSocket, (const struct sockaddr*) &serverAddress, serverLen);
+       SysTryCatch(NID_IO, ret != -1, r = E_SYSTEM, E_SYSTEM,
+                       "[E_SYSTEM] Failed to bind a socket(%d, %s): %s", serverSocket, pSocketName, strerror(errno));
+
+       ret = chmod(pSocketName, 0666);
+       SysTryCatch(NID_IO, ret == 0, r = E_SYSTEM, E_SYSTEM,
+                       "[E_SYSTEM] Failed to change permission of a socket(%d, %s): %s", serverSocket,
+                       pSocketName, strerror(errno));
+
+       listen(serverSocket, 5);
+
+       pGIOChannel = g_io_channel_unix_new(serverSocket);
+       SysTryCatch(NID_IO, pGIOChannel != null, r = E_SYSTEM, E_SYSTEM,
+                       "[E_SYSTEM] Failed to create GIOChannel for socket.");
+
+       // socket will be closed when pGIOChannel is deleted.
+       g_io_channel_set_close_on_unref(pGIOChannel, TRUE);
+       serverSocket = -1;
+
+       pGSource = g_io_create_watch(pGIOChannel, (GIOCondition)(G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP));
+       SysTryCatch(NID_IO, pGSource != null, r = E_SYSTEM, E_SYSTEM,
+                       "[E_SYSTEM] Failed to create GSource for socket.");
+
+       // channel will be delete when pGSource is deleted.
+       g_io_channel_unref(pGIOChannel);
+       pGIOChannel = null;
+
+       g_source_set_callback(pGSource, (GSourceFunc) OnConnectionRequest, this, NULL);
+       g_source_attach(pGSource, __pGMainContext);
+
+       __pConnectGSource = pGSource;
+
+       return E_SUCCESS;
+
+CATCH:
+       if (pGIOChannel != null)
+       {
+               g_io_channel_unref(pGIOChannel);
+       }
+
+       if (serverSocket != -1)
+       {
+               close(serverSocket);
+       }
+
+       if (__pGMainContext)
+       {
+               g_main_context_unref(__pGMainContext);
+               __pGMainContext = null;
+       }
+
+       return r;
+}
+
+void
+_ChannelCAppStub::SetChannelService(_ChannelService& service)
+{
+       __pChannelService = &service;
+}
+
+struct HelloMessage
+{
+       int pid;
+       char appId[256];
+};
+
+gboolean
+_ChannelCAppStub::OnConnectionRequest(GIOChannel* source, GIOCondition condition, gpointer data)
+{
+       int serverFd = -1;
+       int clientFd = -1;
+       struct sockaddr_un clientAddress;
+       socklen_t clientLen = sizeof(clientAddress);
+       GSource* pGSource = null;
+       GIOChannel* pGIOChannel = null;
+       GError* pGError = null;
+       _ClientInfo* pClientInfo = null;
+       _ChannelInfo* pChannelInfo = null;
+       HelloMessage helloMessage;
+       int readSize = 0;
+
+       _ChannelCAppStub* pChannelStub = static_cast< _ChannelCAppStub* >(data);
+       SysTryReturn(NID_IO, pChannelStub != null, FALSE, E_SYSTEM,
+                       "[E_SYSTEM] pChannelStub is null.");
+
+       serverFd = g_io_channel_unix_get_fd(source);
+       clientFd = accept(serverFd, (struct sockaddr*) &clientAddress, &clientLen);
+       SysTryReturn(NID_IO, clientFd != -1, E_SYSTEM, FALSE, "[E_SYSTEM] Failed to accept.");
+
+
+       readSize = read(clientFd, &helloMessage, sizeof(helloMessage));
+       helloMessage.appId[255] = '\0';
+
+       SysLog(NID_IO, " >> Channel Service: accepted client fd: %d, client pid: %d, appid: %s",
+                       clientFd, helloMessage.pid, helloMessage.appId);
+
+       pGIOChannel = g_io_channel_unix_new(clientFd);
+       SysTryCatch(NID_IO, pGIOChannel != null, , E_SYSTEM,
+                       "[E_SYSTEM] Failed to create GIOChannel.");
+
+       g_io_channel_set_encoding(pGIOChannel, NULL, &pGError);
+       g_io_channel_set_flags(pGIOChannel, G_IO_FLAG_NONBLOCK, &pGError);
+
+       g_io_channel_set_close_on_unref(pGIOChannel, TRUE);
+       clientFd = -1;
+
+       pClientInfo = pChannelStub->__clients[helloMessage.pid];
+       if (pClientInfo == null) // first connection request from this client
+       {
+               SysLog(NID_IO, "First connection!! [%s]", helloMessage.appId);
+
+               pClientInfo = new (std::nothrow) _ClientInfo;
+               SysTryCatch(NID_IO, pClientInfo != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
+
+               pClientInfo->pChannelStub = pChannelStub;
+               pClientInfo->clientId = helloMessage.pid;
+               pClientInfo->appId = helloMessage.appId;
+
+               pChannelStub->__clients[helloMessage.pid] = pClientInfo;
+       }
+
+       pChannelInfo = new (std::nothrow) _ChannelInfo;
+       SysTryCatch(NID_IO, pChannelInfo != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
+
+       pGSource = g_io_create_watch(pGIOChannel, (GIOCondition) (G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP));
+       g_source_set_callback(pGSource, (GSourceFunc) OnReadMessage, pChannelInfo, NULL);
+       g_source_attach(pGSource, pChannelStub->__pGMainContext);
+
+       pChannelInfo->pClientInfo = pClientInfo;
+       pChannelInfo->pGIOChannel = pGIOChannel;
+       pChannelInfo->pGSource = pGSource;
+
+       pClientInfo->channels.push_back(pChannelInfo);
+
+       // Stores client info to _ChannelService
+       pChannelStub->__pChannelService->RegisterChannel(pClientInfo->appId, helloMessage.pid, pGIOChannel);
+
+       return TRUE;
+
+CATCH:
+       if (pGIOChannel != null)
+       {
+               g_io_channel_unref(pGIOChannel);
+       }
+
+       if (clientFd != -1)
+       {
+               close(clientFd);
+       }
+
+       return FALSE;
+}
+
+gboolean
+_ChannelCAppStub::OnReadMessage(GIOChannel* source, GIOCondition condition, gpointer data)
+{
+       gboolean ret = FALSE;
+
+       _ChannelInfo* pChannelInfo = (_ChannelInfo*) data;
+       _ClientInfo* pClientInfo = pChannelInfo->pClientInfo;
+       _ChannelCAppStub* pChannelStub = (_ChannelCAppStub*) pClientInfo->pChannelStub;
+
+       ret = pChannelStub->HandleReceivedMessage(source, condition, data);
+
+       return ret;
+}
+
+gboolean
+_ChannelCAppStub::HandleReceivedMessage(GIOChannel* source, GIOCondition condition, gpointer data)
+{
+       GIOStatus status;
+       GError* pGError = null;
+       gsize readBytes = 0;
+       result r = E_SUCCESS;
+
+       SysLog(NID_IO, "fd: %d, condition :0x%x", g_io_channel_unix_get_fd(source), condition);
+
+       _ChannelInfo* pChannelInfo = (_ChannelInfo*) data;
+       _ClientInfo* pClientInfo = pChannelInfo->pClientInfo;
+       _ChannelCAppStub* pChannelStub = pClientInfo->pChannelStub;
+
+       if (condition & G_IO_HUP)
+       {
+               SysLog(NID_IO, " G_IO_HUP, the connection is closed");
+               int clientId = pClientInfo->clientId;
+
+               g_io_channel_shutdown(source, FALSE, &pGError);
+
+               for (unsigned int i = 0; i < pClientInfo->channels.size(); i++)
+               {
+                       if (pChannelInfo == pClientInfo->channels[i])
+                       {
+                               pClientInfo->channels.erase(pClientInfo->channels.begin() + i);
+
+                               pChannelInfo->destroySource = false;
+                               delete pChannelInfo;
+
+                               break;
+                       }
+
+               }
+
+               if (pClientInfo->channels.size() == 0)
+               {
+                       SysLog(NID_IO, "All connections of client(%d) are closed. delete client info", clientId);
+
+                       pChannelStub->__pChannelService->UnregisterChannel(clientId);
+
+                       __clients[clientId] = null;
+
+                       delete pClientInfo;
+               }
+
+               return FALSE;
+       }
+       else if (condition & G_IO_IN)
+       {
+               unique_ptr<char[]> pBuffer(new char[MAX_BUFFER_LENGTH]);
+               pGError = null;
+               status = g_io_channel_read_chars(source, pBuffer.get(), MAX_BUFFER_LENGTH, &readBytes, &pGError);
+               if (status != G_IO_STATUS_NORMAL)
+               {
+                       if (status == G_IO_STATUS_EOF || status == G_IO_STATUS_ERROR)
+                       {
+                               if (status == G_IO_STATUS_EOF)
+                               {
+                                       SysLog(NID_IO, "G_IO_STATUS_EOF, the connection is closed.");
+                               }
+                               else
+                               {
+                                       SysLog(NID_IO, "G_IO_STATUS_ERROR, the connection is closed. ");
+                               }
+
+                               pGError = null;
+                               g_io_channel_shutdown(source, FALSE, &pGError);
+
+                               int clientId = pClientInfo->clientId;
+
+                               for (unsigned int i = 0; i < pClientInfo->channels.size(); i++)
+                               {
+                                       if (pChannelInfo == pClientInfo->channels[i])
+                                       {
+                                               pClientInfo->channels.erase(pClientInfo->channels.begin() + i);
+
+                                               //pChannelInfo->destroySource = false;
+                                               pChannelInfo->destroySource = true;
+                                               delete pChannelInfo;
+                                               break;
+                                       }
+                               }
+
+                               if (pClientInfo->channels.size() == 0)
+                               {
+                                       SysLog(NID_IO, "All connections of client(%d) are closed. delete client info", clientId);
+
+                                       pChannelStub->__pChannelService->UnregisterChannel(clientId);
+
+                                       __clients[clientId] = null;
+
+                                       delete pClientInfo;
+                               }
+
+                               return FALSE;
+                       }
+               }
+
+               SysLog(NID_IO, "CAppChannel >> Channel Server: readBytes: %d, readBuf: %s", readBytes, pBuffer.get());
+
+               SysTryReturn(NID_IO, readBytes != 0, FALSE, E_SYSTEM, "[E_SYSTEM] Received data is empty.");
+
+               String srcAppId = pClientInfo->appId;
+
+               // Parse the header
+               string buffer(pBuffer.get());
+               string tokenStr("::");
+               RequestId reqId = 0;
+               size_t pos = 0;
+               size_t lastPos = 0;
+
+               lastPos = buffer.find(tokenStr);
+
+               // AppId
+               String appId((buffer.substr(pos, lastPos-pos)).c_str());
+
+               SysLog(NID_IO, "CAppChannel >> src = %ls / dest = %ls", srcAppId.GetPointer(), appId.GetPointer());
+
+               pos = lastPos + tokenStr.length();
+               lastPos = buffer.find(tokenStr, pos);
+
+               // Request ID
+               string requestId(buffer.substr(pos, lastPos-pos));
+               reqId = atol(requestId.c_str());
+
+               SysLog(NID_IO, "CAppChannel >> requestId = %d", reqId);
+
+               pos = lastPos + tokenStr.length();
+
+               // Parse the data
+               ArrayList list;
+               list.Construct();
+
+               size_t bufferSize = buffer.length();
+               int tokenCount = 0;
+               string token;
+               while (pos < bufferSize)
+               {
+                       // Get length of each token
+                       token = buffer.substr(pos, TOKEN_LENGTH);
+                       pos += TOKEN_LENGTH;
+
+                       if (token == "0000000")
+                       {
+                               SysLog(NID_IO, "CAppChannel >> length = 0, token = empty string");
+                               list.Add(*(new String()));
+                       }
+                       else
+                       {
+                               tokenCount = atoi(token.c_str());
+                               token = buffer.substr(pos, tokenCount);
+                               pos += tokenCount;
+
+                               SysLog(NID_IO, "CAppChannel >> length = %d, token = %s", tokenCount, token.c_str());
+                               list.Add(*(new String(token.c_str())));
+                       }
+               }
+
+               r = pChannelStub->__pChannelService->SendRequest(srcAppId, appId, list, reqId);
+               SysTryReturn(NID_IO, !IsFailed(r), FALSE, E_SYSTEM, "[E_SYSTEM] Failed to send request.");
+
+               list.RemoveAll(true);
+       }
+       else
+       {
+               SysLog(NID_IO, " >> Channel Service: else !!!");
+       }
+
+       return TRUE;
+}
+
+bool
+_ChannelCAppStub::SendResponse(int requestId, void* pGIOChannel, const ArrayList& args)
+{
+       gsize writtenBytes = 0;
+       GError* pGError = null;
+
+       // Parse the data
+       String str;
+       String item;
+       String lengthString;
+       int count = args.GetCount();
+       int itemLength = 0;
+       int paddingLength = 0;
+       result r = E_SUCCESS;
+       SysLog(NID_IO, "item count: %d", count);
+
+       for (int i = 0; i < count; ++i)
+       {
+               item = *((String*)args.GetAt(i));
+               unique_ptr<char[]> pItemStr(_StringConverter::CopyToCharArrayN(item));
+               itemLength = strlen(pItemStr.get());
+               lengthString = Integer::ToString(itemLength);
+               r = item.Insert(lengthString, 0);
+               SysTryReturn(NID_IO, !IsFailed(r), false, E_SYSTEM, "[E_SYSTEM] Failed to compose the response message.");
+
+               // padding 7 digit
+               paddingLength = CAPP_PADDING_LENGTH - lengthString.GetLength();
+               for (int j = 0; j < paddingLength; j++)
+               {
+                       r = item.Insert(L'0', 0);
+                       SysTryReturn(NID_IO, !IsFailed(r), false, E_SYSTEM, "[E_SYSTEM] Failed to compose the response message.");
+               }
+
+               str.Append(item);
+       }
+
+       SysLog(NID_IO, "data: %ls, length: %d", str.GetPointer(), str.GetLength());
+
+       // Add a RequestId
+       str.Append(L"|||");
+       str.Append(requestId);
+       str.Append(L"|");
+
+       // Send a data
+       unique_ptr<char[]> pStr(_StringConverter::CopyToCharArrayN(str));
+
+       itemLength = strlen(pStr.get());
+
+       g_io_channel_write_chars((GIOChannel*)pGIOChannel, (char*)pStr.get(), itemLength, &writtenBytes, &pGError);
+       g_io_channel_flush((GIOChannel*)pGIOChannel, &pGError);
+
+       return true;
+}
+
+}}
+
diff --git a/src/FIo_ChannelService.cpp b/src/FIo_ChannelService.cpp
new file mode 100644 (file)
index 0000000..dd79574
--- /dev/null
@@ -0,0 +1,323 @@
+//
+// Open Service Platform
+// Copyright (c) 2012 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+/**
+ * @file       FIo_ChannelService.cpp
+ * @brief      This is the implementation file for the _ChannelService class.
+ *
+ */
+
+#include <vector>
+#include <new>
+#include <glib.h>
+
+#include <unique_ptr.h>
+
+#include <FBaseStringComparer.h>
+#include <FBaseSysLog.h>
+#include <FBase_StringConverter.h>
+#include <FBaseRt_EventDispatcher.h>
+#include "FIo_ChannelService.h"
+#include "FIo_ChannelMessages.h"
+#include "FIo_IChannelServiceStub.h"
+#include "FIo_ChannelCAppStub.h"
+#include "FIo_ChannelWebAppStub.h"
+
+using namespace std;
+using namespace Tizen::Base;
+using namespace Tizen::Base::Collection;
+using namespace Tizen::Base::Runtime;
+using namespace Tizen::Io;
+
+
+namespace Tizen { namespace Io
+{
+
+_ChannelService::_ChannelService(void)
+       : __pIChannelServiceStub(null)
+{
+
+}
+
+_ChannelService::~_ChannelService(void)
+{
+
+}
+
+result
+_ChannelService::Construct(_IChannelServiceStub& stub)
+{
+       static _StringHashProvider hashProvider;
+       static _StringComparer stringComparer;
+       result r = E_SUCCESS;
+
+       __channels.Construct(0, 0, hashProvider, stringComparer);
+
+       __pIChannelServiceStub = &stub;
+
+       __pIChannelServiceStub->SetChannelService(*this);
+
+       // Create a CAppStub
+       unique_ptr<_ChannelCAppStub> pCStub(new (std::nothrow) _ChannelCAppStub());
+       SysTryReturnResult(NID_IO, pCStub != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
+
+       r = pCStub->Construct();
+       SysTryReturnResult(NID_IO, r == E_SUCCESS, E_SYSTEM, "Failed to create a CAppStub.");
+
+       pCStub->SetChannelService(*this);
+
+       // Create a WebAppStub
+       unique_ptr<_ChannelWebAppStub> pWebStub(new (std::nothrow) _ChannelWebAppStub());
+       SysTryReturnResult(NID_IO, pWebStub != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
+
+       r = pWebStub->Construct();
+       SysTryReturnResult(NID_IO, r == E_SUCCESS, E_SYSTEM, "Failed to create a WebAppStub.");
+
+       pWebStub->SetChannelService(*this);
+
+       pCStub.release();
+       pWebStub.release();
+
+       return E_SUCCESS;
+}
+
+result
+_ChannelService::RegisterChannel(const String& channelId, const _IChannelServiceEventListener& listener)
+{
+       return E_SUCCESS;
+}
+
+result
+_ChannelService::RegisterChannel(const String& channelId, int clientId, unsigned int type)
+{
+       result r = E_SUCCESS;
+       _ChannelInfo* pChannelInfo = null;
+
+       SysLog(NID_IO, "Register a channel : %ls.", channelId.GetPointer());
+
+       r = __channels.GetValue(channelId, pChannelInfo);
+       SysTryReturnResult(NID_IO, pChannelInfo == null, E_SYSTEM,  "Channel has already been registered.");
+
+       pChannelInfo = new (std::nothrow) _ChannelInfo;
+       SysTryReturnResult(NID_IO, pChannelInfo != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
+
+       pChannelInfo->channelId = channelId;
+       pChannelInfo->clientId = clientId;
+       pChannelInfo->type = type;
+       pChannelInfo->pGIOChannel = null;
+
+       __channels.Add(channelId, pChannelInfo);
+
+       return E_SUCCESS;
+}
+
+result
+_ChannelService::RegisterChannel(const String& channelId, int clientId, void* pGIOChannel)
+{
+       result r = E_SUCCESS;
+       _ChannelInfo* pChannelInfo = null;
+
+       SysLog(NID_IO, "Register a channel : [%ls]", channelId.GetPointer());
+
+       r = __channels.GetValue(channelId, pChannelInfo);
+       SysTryReturnResult(NID_IO, pChannelInfo == null, E_SYSTEM, "Channel has already been registered.");
+
+       pChannelInfo = new (std::nothrow) _ChannelInfo;
+       SysTryReturnResult(NID_IO, pChannelInfo != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
+
+       pChannelInfo->channelId = channelId;
+       pChannelInfo->clientId = clientId;
+       pChannelInfo->type = CAPP_CHANNEL;
+       pChannelInfo->pGIOChannel = pGIOChannel;
+
+       __channels.Add(channelId, pChannelInfo);
+
+       return E_SUCCESS;
+}
+
+result
+_ChannelService::UnregisterChannel(const String& channelId)
+{
+       return E_SUCCESS;
+}
+
+result
+_ChannelService::UnregisterChannel(int clientId)
+{
+       SysLog(NID_IO, "Unregister - clientId =  %d", clientId);
+
+       result r = E_OBJ_NOT_FOUND;
+
+       String key;
+       _ChannelInfo* pValue = null;
+       IListT<String>* pKeys = __channels.GetKeysN();
+       SysTryReturnResult(NID_IO, pKeys != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
+
+       int count = __channels.GetCount();
+
+       for (int i = 0; i < count; i++)
+       {
+               pKeys->GetAt(i, key);
+               __channels.GetValue(key, pValue);
+               if (pValue != null && pValue->clientId == clientId)
+               {
+                       SysLog(NID_IO, "Unregister - ChannelId = %ls", key.GetPointer());
+                       __channels.Remove(key);
+                       delete pValue;
+
+                       r = E_SUCCESS;
+               }
+       }
+
+       delete pKeys;
+
+       return r;
+}
+
+result
+_ChannelService::SendRequest(const String& src,
+                                                        const String& dest,
+                                                        const ArrayList& args,
+                                                        int requestId)
+{
+       SysLog(NID_IO, "[%ls] ---> [%ls], Request ID = %d", src.GetPointer(), dest.GetPointer(), requestId);
+
+       _ChannelInfo* pChannelInfo = null;
+
+       __channels.GetValue(dest, pChannelInfo);
+       SysTryReturnResult(NID_IO, pChannelInfo != null, E_OBJ_NOT_FOUND,
+                               "Destination channel is not found.");
+
+       // Channel for WebApp
+       if (pChannelInfo->type == WEBAPP_CHANNEL)
+       {
+               bool ret = _ChannelWebAppStub::SendResponse(pChannelInfo->clientId, args);
+               SysTryReturnResult(NID_IO, ret, E_SYSTEM, "Failed to send the data to a WebApp.");
+       }
+       // Channel for OspApp
+       else
+       {
+               result r = __pIChannelServiceStub->SendRequest(pChannelInfo->clientId, src, dest, args, requestId);
+               SysTryReturnResult(NID_IO, r == E_SUCCESS, E_SYSTEM, "Failed to send the request data.");
+       }
+
+       return E_SUCCESS;
+}
+
+result
+_ChannelService::SendNullRequest(const String& src,
+                                                        const String& dest,
+                                                        int requestId)
+{
+       SysLog(NID_IO, "[%ls] ---> [%ls], Request ID = %d", src.GetPointer(), dest.GetPointer(), requestId);
+
+       _ChannelInfo* pChannelInfo = null;
+
+       __channels.GetValue(dest, pChannelInfo);
+       SysTryReturnResult(NID_IO, pChannelInfo != null, E_OBJ_NOT_FOUND,
+                               "Destination channel is not found.");
+
+       // Channel for WebApp
+       if (pChannelInfo->type == WEBAPP_CHANNEL)
+       {
+               SysLog(NID_IO, "WebApp Channel, the data are not JSON types");
+               return E_SYSTEM;
+       }
+       // Channel for OspApp
+       else
+       {
+               __pIChannelServiceStub->SendNullRequest(pChannelInfo->clientId, src, dest, requestId);
+       }
+
+       return E_SUCCESS;
+}
+
+result
+_ChannelService::SendResponse(const String& src,
+                                                         const String& dest,
+                                                         const ArrayList& args,
+                                                         int requestId)
+{
+       SysLog(NID_IO, "[%ls] ---> [%ls], Request ID = %d", src.GetPointer(), dest.GetPointer(), requestId);
+
+       _ChannelInfo* pChannelInfo = null;
+
+       __channels.GetValue(dest, pChannelInfo);
+       SysTryReturnResult(NID_IO, pChannelInfo != null, E_OBJ_NOT_FOUND,
+                               "Destination channel not found.");
+
+       // Channel for WebApp
+       if (pChannelInfo->type == WEBAPP_CHANNEL)
+       {
+               bool ret = _ChannelWebAppStub::SendResponse(pChannelInfo->clientId, args);
+               SysTryReturnResult(NID_IO, ret, E_SYSTEM, "Failed to send the data to a WebApp.");
+       }
+       // Channel for CApp
+       else if (pChannelInfo->type == CAPP_CHANNEL)
+       {
+               bool ret = _ChannelCAppStub::SendResponse(requestId, pChannelInfo->pGIOChannel, args);
+               SysTryReturnResult(NID_IO, ret, E_SYSTEM, "Failed to send the data to a CApp.");
+       }
+       // Channel for OspApp
+       else
+       {
+               result r = __pIChannelServiceStub->SendResponse(pChannelInfo->clientId, src, dest, args, requestId);
+               SysTryReturnResult(NID_IO, r == E_SUCCESS, E_SYSTEM, "Failed to send the response data");
+       }
+
+       return E_SUCCESS;
+}
+
+result
+_ChannelService::SendNullResponse(const String& src,
+                                                         const String& dest,
+                                                         int requestId)
+{
+       SysLog(NID_IO, "[%ls] ---> [%ls], Request ID = %d", src.GetPointer(), dest.GetPointer(), requestId);
+
+       _ChannelInfo* pChannelInfo = null;
+
+       __channels.GetValue(dest, pChannelInfo);
+       SysTryReturnResult(NID_IO, pChannelInfo != null, E_OBJ_NOT_FOUND,
+                               "Destination channel not found.");
+
+       // Channel for WebApp
+       if (pChannelInfo->type == WEBAPP_CHANNEL)
+       {
+               SysLog(NID_IO, "WebApp Channel, the data are not JSON types");
+               return E_SYSTEM;
+       }
+       // Channel for OspApp
+       else
+       {
+               __pIChannelServiceStub->SendNullResponse(pChannelInfo->clientId, src, dest, requestId);
+       }
+
+       return E_SUCCESS;
+}
+
+bool
+_ChannelService::IsChannelRegistered(const String& channelId)
+{
+       bool out = false;
+
+       __channels.ContainsKey(channelId, out);
+
+       return out;
+}
+
+}}
diff --git a/src/FIo_ChannelServiceStub.cpp b/src/FIo_ChannelServiceStub.cpp
new file mode 100644 (file)
index 0000000..f9abe4a
--- /dev/null
@@ -0,0 +1,230 @@
+//
+// Open Service Platform
+// Copyright (c) 2012 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+/**
+ * @file       FIo_ChannelServiceStub.cpp
+ * @brief      This is the implementation file for the  _ChannelServiceStub class.
+ *
+ */
+
+#include <string>
+#include <vector>
+#include <iostream>
+#include <new>
+
+#include <FBaseSysLog.h>
+#include <FBaseRt_EventDispatcher.h>
+#include "FIo_IpcServer.h"
+#include "FIo_ChannelServiceStub.h"
+#include "FIo_ChannelMessages.h"
+#include "FIo_ChannelService.h"
+
+using namespace Tizen::Base;
+using namespace Tizen::Base::Collection;
+using namespace Tizen::Base::Runtime;
+using namespace Tizen::Io;
+
+using namespace std;
+
+namespace Tizen { namespace Io
+{
+
+_ChannelServiceStub::_ChannelServiceStub(void)
+       : __pIpcServer(null)
+       , __pChannelService(null)
+{
+
+}
+
+_ChannelServiceStub::~_ChannelServiceStub(void)
+{
+       delete __pIpcServer;
+}
+
+result
+_ChannelServiceStub::Construct(void)
+{
+       SysAssertf(__pIpcServer == null, "Already constructed. Calling Construct() twice or more on a same instance is not allowed for this class.");
+       SysLog(NID_IO, "Constructed");
+
+       result r = E_SUCCESS;
+       _IpcServer* pIpcServer = null;
+
+       pIpcServer = new (std::nothrow) _IpcServer;
+       SysTryReturnResult(NID_IO, pIpcServer != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
+
+       r = pIpcServer->Construct("osp.io.ipcserver.channelmanager", *this, false);
+       SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to create IPC server(ChannelService)", GetErrorMessage(r));
+
+       __pIpcServer = pIpcServer;
+
+       return E_SUCCESS;
+
+CATCH:
+       delete pIpcServer;
+
+       return r;
+}
+
+void
+_ChannelServiceStub::SetChannelService(_ChannelService& service)
+{
+       __pChannelService = &service;
+}
+
+bool
+_ChannelServiceStub::OnRegisterChannelMessage(const Tizen::Base::String& appId, int* pResult)
+{
+       SysAssertf(__pChannelService != null, "Channel service has not been initialized.\n");
+
+       int clientId = __pIpcServer->GetClientId();
+
+       *pResult = __pChannelService->RegisterChannel(appId, clientId);
+
+       return true;
+}
+
+bool
+_ChannelServiceStub::OnSendRequestMessage(const String& src,
+                                                                                 const String& dest,
+                                                                                 const ArrayList& args,
+                                                                                 int requestId,
+                                                                                 int* pResult)
+{
+       SysAssertf(__pChannelService != null, "Channel service has not been initialized.\n");
+
+       *pResult = __pChannelService->SendRequest(src, dest, args, requestId);
+
+       const_cast<ArrayList*>(&args)->RemoveAll(true);
+
+       return true;
+}
+
+bool
+_ChannelServiceStub::OnSendNullRequestMessage(const String& src,
+                                                                                 const String& dest,
+                                                                                 int requestId,
+                                                                                 int* pResult)
+{
+       SysAssertf(__pChannelService != null, "Channel service has not been initialized.\n");
+
+       *pResult = __pChannelService->SendNullRequest(src, dest, requestId);
+
+       return true;
+}
+
+bool
+_ChannelServiceStub::OnSendResponseMessage(const String& src,
+                                                                                  const String& dest,
+                                                                                  const ArrayList& args,
+                                                                                  int requestId,
+                                                                                  int* pResult)
+{
+       SysAssertf(__pChannelService != null, "Channel service has not been initialized.\n");
+
+       *pResult = __pChannelService->SendResponse(src, dest, args, requestId);
+
+       const_cast<ArrayList*>(&args)->RemoveAll(true);
+
+       return true;
+}
+
+bool
+_ChannelServiceStub::OnSendNullResponseMessage(const String& src,
+                                                                                  const String& dest,
+                                                                                  int requestId,
+                                                                                  int* pResult)
+{
+       SysAssertf(__pChannelService != null, "Channel service has not been initialized.\n");
+
+       *pResult = __pChannelService->SendNullResponse(src, dest, requestId);
+
+       return true;
+}
+
+result
+_ChannelServiceStub::SendRequest(int clientId, const String& src, const String& dest, const ArrayList& args, int requestId)
+{
+       SysAssertf(__pIpcServer != null, "Not yet constructed. Construct() should be called before use.\n");
+
+       return __pIpcServer->SendResponse(clientId, new ChannelServiceMsg_sendRequestAsync(src, dest, args, requestId));
+}
+
+result
+_ChannelServiceStub::SendNullRequest(int clientId, const String& src, const String& dest, int requestId)
+{
+       SysAssertf(__pIpcServer != null, "Not yet constructed. Construct() should be called before use.\n");
+
+       return __pIpcServer->SendResponse(clientId, new ChannelServiceMsg_sendNullRequestAsync(src, dest, requestId));
+}
+
+result
+_ChannelServiceStub::SendResponse(int clientId, const String& src, const String& dest, const ArrayList& args, int requestId)
+{
+       SysAssertf(__pIpcServer != null, "Not yet constructed. Construct() should be called before use.\n");
+
+       return __pIpcServer->SendResponse(clientId, new ChannelServiceMsg_sendResponseAsync(src, dest, args, requestId));
+}
+
+result
+_ChannelServiceStub::SendNullResponse(int clientId, const String& src, const String& dest, int requestId)
+{
+       SysAssertf(__pIpcServer != null, "Not yet constructed. Construct() should be called before use.\n");
+
+       return __pIpcServer->SendResponse(clientId, new ChannelServiceMsg_sendNullResponseAsync(src, dest, requestId));
+}
+
+void
+_ChannelServiceStub::OnIpcRequestReceived(_IpcServer& server, const IPC::Message& message)
+{
+       IPC_BEGIN_MESSAGE_MAP(_ChannelServiceStub, message)
+       IPC_MESSAGE_HANDLER_EX(ChannelServiceMsg_register, &server, OnRegisterChannelMessage)
+       IPC_MESSAGE_HANDLER_EX(ChannelServiceMsg_sendRequest, &server, OnSendRequestMessage)
+       IPC_MESSAGE_HANDLER_EX(ChannelServiceMsg_sendNullRequest, &server, OnSendNullRequestMessage)
+       IPC_MESSAGE_HANDLER_EX(ChannelServiceMsg_sendResponse, &server, OnSendResponseMessage)
+       IPC_MESSAGE_HANDLER_EX(ChannelServiceMsg_sendNullResponse, &server, OnSendNullResponseMessage)
+       IPC_END_MESSAGE_MAP_EX()
+}
+
+void
+_ChannelServiceStub::OnIpcServerStarted(const _IpcServer& server)
+{
+
+}
+
+void
+_ChannelServiceStub::OnIpcServerStopped(const _IpcServer& server)
+{
+
+}
+
+void
+_ChannelServiceStub::OnIpcClientConnected(const _IpcServer& server, int clientId)
+{
+
+}
+
+void
+_ChannelServiceStub::OnIpcClientDisconnected(const _IpcServer& server, int clientId)
+{
+       SysAssertf(__pChannelService != null, "Channel service has not been initialized.\n");
+       SysLog(NID_IO, "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
+       __pChannelService->UnregisterChannel(clientId);
+       SysLog(NID_IO, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
+}
+
+}}
diff --git a/src/FIo_ChannelWebAppStub.cpp b/src/FIo_ChannelWebAppStub.cpp
new file mode 100644 (file)
index 0000000..fe2fb6d
--- /dev/null
@@ -0,0 +1,1125 @@
+//
+// Open Service Platform
+// Copyright (c) 2012 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+/**
+ * @file       FIo_ChannelWebAppStub.cpp
+ * @brief      This is the implementation file for the  _ChannelWebAppStub class.
+ *
+ */
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <cerrno>
+#include <iostream>
+#include <sstream>
+
+#include <unique_ptr.h>
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+#include <openssl/md5.h>
+#include <openssl/sha.h>
+#include <openssl/bio.h>
+#include <openssl/evp.h>
+#include <openssl/buffer.h>
+
+#include <FBase_StringConverter.h>
+#include <FBaseDataType.h>
+#include <FBaseLong.h>
+#include <FBaseColArrayList.h>
+
+#include <FBaseRt_EventDispatcher.h>
+#include <FBaseSysLog.h>
+#include <FBaseUtilStringTokenizer.h>
+#include <FIo_ChannelServiceStub.h>
+#include <FApp_AppInfo.h>
+
+#include "FIo_ChannelWebAppStub.h"
+
+#define MAX_BUFFER_LENGTH 4096
+
+#define htonll(x)   ((((uint64_t)htonl(x)) << 32) + htonl(x >> 32))
+#define ntohll(x)   ((((uint64_t)ntohl(x)) << 32) + ntohl(x >> 32))
+
+using namespace std;
+
+using namespace Tizen::Base;
+using namespace Tizen::Base::Collection;
+using namespace Tizen::Base::Runtime;
+using namespace Tizen::Base::Utility;
+using namespace Tizen::Io;
+using namespace Tizen::App;
+
+namespace Tizen { namespace Io
+{
+
+static const size_t _MAX_CONNECTIONS = 10;
+static const size_t _MAX_BUFFER_SIZE = 1024;
+static const int _PORT = 8080;
+
+//static const char* webSocketServerAddr = "127.0.0.1";
+static const char* webSocketHeaderId("Upgrade"); // web socket header identifier
+static const char* webSocketHeaderKey("Sec-WebSocket-Key"); // hybi10
+static const char* webSocketHeaderKey1("Sec-WebSocket-Key1"); // hybi00
+static const char* webSocketHeaderKey2("Sec-WebSocket-Key2"); // hybi00
+static const char* webSocketHeaderIdHybi10("websocket");
+static const char* webSocketHeaderIdHybi00("WebSocket");
+static const char* webSocketMagicString("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
+
+static const int _CHALLENGE_NUMBER_SIZE = 4;
+static const int _CHALLENGE_THIRD_INFO_SIZE = 8;
+static const int _CHALLENGE_RESPONSE_SIZE = 16;
+
+const unsigned char _SIMPLE_PAYLOAD_MAX_LEN = 125;
+const unsigned char _EXTEND_PAYLOAD_TYPE_LEN16 = 0x7e; //126
+const unsigned char _EXTEND_PAYLOAD_TYPE_LEN64 = 0x7f; //127
+
+WebSocketType gHeaderType = WS_NONE;
+
+enum WebSocketOpcode
+{
+       OPCODE_CONTINUE = 0x0,
+       OPCODE_TEXT_MESSAGE = 0x1,
+       OPCODE_BIN_MESSAGE = 0x2,
+       OPCODE_CONNECTION_CLOSE = 0x8,
+       OPCODE_PING = 0x9,
+       OPCODE_PONG = 0xA
+};
+
+
+_ChannelWebAppStub::_WebSocketMessage::_WebSocketMessage(void)
+       : m_payloadOffset(0)
+       , m_payloadLen(0)
+       , m_headerParsed(false)
+       , m_payload(null)
+{
+}
+
+_ChannelWebAppStub::_WebSocketMessage::~_WebSocketMessage(void)
+{
+       delete[] m_payload;
+}
+
+size_t
+_ChannelWebAppStub::_WebSocketMessage::CreateMessage(std::string& payload, std::string& message)
+{
+       message.clear();
+       uint8_t *pCurrent = reinterpret_cast<uint8_t*>(const_cast<char *>(message.c_str()));
+       uint8_t *pStart = pCurrent;
+
+       // fin: 1 , opcode: 1
+       *pCurrent |= 0x81;
+       pCurrent++;
+       // masked : 0 (no mask)
+       *pCurrent &= 0x00;
+
+       // set payload len
+       if (payload.size() > _SIMPLE_PAYLOAD_MAX_LEN)
+       {
+               if (payload.size() < 64 * 1024)
+               {
+                       *pCurrent |= _EXTEND_PAYLOAD_TYPE_LEN16;
+                       pCurrent++;
+                       uint16_t length = payload.size();
+
+                       // Change the byte order
+                       length = htons(length);
+
+                       memcpy(pCurrent, &length, 2);
+                       pCurrent = pCurrent + 2;
+               }
+               else
+               {
+                       *pCurrent |= _EXTEND_PAYLOAD_TYPE_LEN64;
+                       pCurrent++;
+                       uint64_t length = payload.size();
+
+                       // Change the byte order
+                       length = htonll(length);
+
+                       memcpy(pCurrent, &length, 8);
+                       pCurrent = pCurrent + 8;
+               }
+       }
+       else
+       {
+               *pCurrent |= payload.size();
+               pCurrent++;
+       }
+
+       memcpy(pCurrent, payload.c_str(), payload.size());
+       pCurrent = pCurrent + payload.size();
+       //*pCurrent = '\0';
+       //pCurrent++;
+
+       return pCurrent - pStart;
+}
+
+int
+_ChannelWebAppStub::_WebSocketMessage::ParseHeader(uint8_t* message, int messageLen)
+{
+       SysTryLogReturn(NID_IO, message != null, -1, "message is null");
+
+       SysLog(NID_IO, "message = %s, size = %d", message, messageLen);
+
+       uint8_t* pCurrent = message;
+
+       // check 'fin' bit
+       m_header.factors.fin = 0x1 & *pCurrent >> 7;
+       // check 'opcode' bit
+       m_header.factors.opcode = 0xf & *pCurrent;
+       pCurrent++;
+
+       // check 'masked' bit
+       m_header.factors.masked = 0x1 & *pCurrent >> 7;
+       // check 'payload' type bit
+       m_header.factors.payloadLen = 0x7f & *pCurrent;
+       pCurrent++;
+
+       // set payload length
+       m_payloadLen = 0;
+       if (m_header.factors.payloadLen == _EXTEND_PAYLOAD_TYPE_LEN16)
+       {
+               SysLog(NID_IO, "extended payload len 16");
+
+               uint16_t length = 0;
+               memcpy(&length, pCurrent, 2);
+
+               // Change the byte order
+               m_payloadLen = ntohs(length);
+
+               pCurrent = pCurrent + 2; // jump two byte
+       }
+       else if (m_header.factors.payloadLen == _EXTEND_PAYLOAD_TYPE_LEN64)
+       {
+               SysLog(NID_IO, "extended payload len 64");
+
+               uint64_t length = 0;
+               memcpy(&length, pCurrent, 8);
+
+               // Change the byte order
+               m_payloadLen = ntohll(length);
+
+               pCurrent = pCurrent + 8; // jump eight byte
+       }
+       else
+       {
+               SysLog(NID_IO, "default payload len");
+               m_payloadLen = m_header.factors.payloadLen;
+       }
+
+       SysLog(NID_IO, "m_payloadLen = %lld", m_payloadLen);
+
+       SysTryLogReturn(NID_IO, m_payloadLen <= (uint64_t)messageLen, -1, "header parsing error!");
+
+       // set masking-key
+       if (m_header.factors.masked == 1)
+       {
+               memcpy(m_maskingKey, pCurrent, 4);
+               pCurrent = pCurrent + 4; // jump four byte
+       }
+
+       m_payloadOffset = pCurrent - message;
+       m_headerParsed = true;
+
+       SysLog(NID_IO, "m_payloadOffset = %d", m_payloadOffset);
+
+       return 0;
+}
+
+int
+_ChannelWebAppStub::_WebSocketMessage::ParsePayload(uint8_t* message, int messageLen)
+{
+       SysTryLogReturn(NID_IO, message != null, -1, "message is null");
+
+       SysLog(NID_IO, "message = %s", message);
+
+       SysTryLogReturn(NID_IO, m_payloadLen <= (uint64_t)messageLen, -1, "payloadLen is invalid!");
+       SysTryLogReturn(NID_IO, m_headerParsed == true, -1, "header not existed!");
+
+       // set payload length
+       m_payload = new (std::nothrow) uint8_t[m_payloadLen + 1];
+       SysTryLogReturn(NID_IO, m_payload != null, -1, "[E_OUT_OF_MEMORY] The memory is insufficient.");
+
+       memcpy(m_payload, message + m_payloadOffset, m_payloadLen);
+
+       // apply masking key to payload
+       if (m_header.factors.masked == 1)
+       {
+               uint8_t *payload = m_payload;
+               for (uint64_t i = 0; i < m_payloadLen; i++)
+               {
+                       payload[i] ^= m_maskingKey[i % 4];
+               }
+               payload[m_payloadLen] = '\0';
+       }
+
+       return 0;
+}
+
+void
+_ChannelWebAppStub::_WebSocketMessage::ConsoleMessage(void) const
+{
+       SysLog(NID_IO, "fin: %d", static_cast<bool>(m_header.factors.fin));
+       SysLog(NID_IO, "masked: %d", static_cast<bool>(m_header.factors.masked));
+       SysLog(NID_IO, "opcode: %d", static_cast<uint8_t>(m_header.factors.opcode));
+       SysLog(NID_IO, "payload: %s", m_payload);
+       SysLog(NID_IO, "payload len: %d", m_payloadLen);
+}
+
+_ChannelWebAppStub::_ChannelInfo::_ChannelInfo(void)
+       : pClientInfo(null)
+       , pGIOChannel(null)
+       , pGSource(null)
+       , destroySource(true)
+{
+}
+
+_ChannelWebAppStub::_ChannelInfo::~_ChannelInfo(void)
+{
+       if (pGIOChannel != null)
+       {
+               g_io_channel_unref(pGIOChannel);
+       }
+
+       if (pGSource != null)
+       {
+               if (destroySource)
+               {
+                       g_source_destroy(pGSource);
+               }
+
+               g_source_unref(pGSource);
+       }
+}
+
+_ChannelWebAppStub::_ClientInfo::_ClientInfo(void)
+       : pChannelStub(null)
+{
+}
+
+_ChannelWebAppStub::_ClientInfo::~_ClientInfo(void)
+{
+       channels.clear();
+}
+
+_ChannelWebAppStub::_ChannelWebAppStub(void)
+       : __pChannelService(null)
+       , __pGMainContext(null)
+       , __pServerGSource(null)
+       , __pClientGSource(null)
+       , __pClients(null)
+{
+}
+
+_ChannelWebAppStub::~_ChannelWebAppStub(void)
+{
+       if (__pServerGSource != null)
+       {
+               g_source_destroy(__pServerGSource);
+               g_source_unref(__pServerGSource);
+               __pServerGSource = null;
+       }
+}
+
+result
+_ChannelWebAppStub::Construct(void)
+{
+       GSource* pGSource = null;
+       GIOChannel* pGIOChannel = null;
+       struct sockaddr_in socketInfo;
+       int serverSocket = -1;
+       int ret = 0;
+       result r = E_SUCCESS;
+
+       __pClients = new (std::nothrow) HashMap();
+       SysTryReturnResult(NID_IO, __pClients != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
+       __pClients->Construct(50);
+
+       __pGMainContext = g_main_context_get_thread_default(); //get own gmain context except default thread
+       if (__pGMainContext == null)
+       {
+               __pGMainContext = g_main_context_default(); //get gmain context from me (default)
+               SysTryReturnResult(NID_IO, __pGMainContext != null, E_SYSTEM,
+                               "Failed to get glib context.");
+       }
+
+       // create native socket
+       // set non-blocking socket mode
+       serverSocket = socket(AF_INET,
+                     SOCK_STREAM | SOCK_NONBLOCK,
+                     IPPROTO_TCP);
+
+       SysTryReturnResult(NID_IO, serverSocket != -1, E_SYSTEM,
+                       "Failed to create a socket.");
+
+       int reuse = 1;
+       ret = setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse));
+       SysTryCatch(NID_IO, ret != -1, r = E_SYSTEM, E_SYSTEM,
+                       "[E_SYSTEM] Failed to set options on socket(%d, %s): %d", serverSocket, strerror(errno), errno);
+
+       // create native socket of server
+       memset(&socketInfo, 0, sizeof(socketInfo));
+       socketInfo.sin_family = AF_INET;
+       //socketInfo.sin_addr.s_addr = inet_addr(webSocketServerAddr);
+       //socketInfo.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+       socketInfo.sin_addr.s_addr = htonl(INADDR_ANY);
+       socketInfo.sin_port = htons(_PORT);
+
+       // bind local address
+       ret = bind(serverSocket,
+                       (const struct sockaddr*) &socketInfo,
+                       sizeof(struct sockaddr_in));
+       SysTryCatch(NID_IO, ret != -1, r = E_SYSTEM, E_SYSTEM,
+                       "[E_SYSTEM] Failed to bind a socket(%d, %s): %d", serverSocket, strerror(errno), errno);
+
+       listen(serverSocket, _MAX_CONNECTIONS);
+
+       pGIOChannel = g_io_channel_unix_new(serverSocket);
+       SysTryCatch(NID_IO, pGIOChannel != null, r = E_SYSTEM, E_SYSTEM,
+                       "[E_SYSTEM] Failed to create GIOChannel for socket.");
+
+       // socket will be closed when pGIOChannel is deleted.
+       g_io_channel_set_close_on_unref(pGIOChannel, TRUE);
+       serverSocket = -1;
+
+       pGSource = g_io_create_watch(pGIOChannel, (GIOCondition)(G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP));
+       SysTryCatch(NID_IO, pGSource != null, r = E_SYSTEM, E_SYSTEM,
+                       "[E_SYSTEM] Failed to create GSource for socket.");
+
+       // channel will be delete when pGSource is deleted.
+       g_io_channel_unref(pGIOChannel);
+       pGIOChannel = null;
+
+       g_source_set_callback(pGSource, (GSourceFunc) OnConnectionRequest, this, NULL);
+       g_source_attach(pGSource, __pGMainContext);
+
+       __pServerGSource = pGSource;
+
+       return E_SUCCESS;
+
+CATCH:
+       if (pGIOChannel != null)
+       {
+               g_io_channel_unref(pGIOChannel);
+       }
+
+       if (serverSocket != -1)
+       {
+               close(serverSocket);
+       }
+
+       if (__pGMainContext)
+       {
+               g_main_context_unref(__pGMainContext);
+               __pGMainContext = null;
+       }
+
+       return r;
+}
+
+void
+_ChannelWebAppStub::SetChannelService(_ChannelService& service)
+{
+       __pChannelService = &service;
+}
+
+gboolean
+_ChannelWebAppStub::OnConnectionRequest(GIOChannel* source, GIOCondition condition, gpointer data)
+{
+       int serverFd = -1;
+       int clientFd = -1;
+       struct sockaddr_in socketInfo;
+       socklen_t socketInfoLength = sizeof(socketInfo);
+       GSource* pGSource = null;
+       GIOChannel* pGIOChannel = null;
+       GError* pGError = null;
+       _ClientInfo* pClientInfo = null;
+       _ChannelInfo* pChannelInfo = null;
+       WebSocketType headerType;
+       SoupMessageHeaders* pSoupHeader = null;
+       int len = -1;
+       bool out = false;
+
+       AppId srcAppId;
+       AppId destAppId;
+       String key;
+
+       _ChannelWebAppStub* pChannelStub = static_cast< _ChannelWebAppStub* >(data);
+       SysTryReturn(NID_IO, pChannelStub != null, FALSE, E_SYSTEM,
+                       "[E_SYSTEM] pChannelStub is null.");
+
+       serverFd = g_io_channel_unix_get_fd(source);
+
+       clientFd = accept(serverFd,
+                                       (struct sockaddr*) &socketInfo,
+                                       &socketInfoLength);
+       SysTryReturn(NID_IO, clientFd != -1, FALSE, E_SYSTEM, "[E_SYSTEM] Failed to accept.");
+
+       // Get a http header
+       std::string headerData;
+       char header[_MAX_BUFFER_SIZE + 1] = {0,};
+       int headerLength = recv(clientFd, (char*)(header), _MAX_BUFFER_SIZE, 0);
+       if (headerLength < 0)
+       {
+               SysLog(NID_IO, "errno = %d %s", errno, strerror(errno));
+               SysLog(NID_IO, "headerLength = %d", headerLength);
+               SysLog(NID_IO, "Recv header = %s", header);
+
+               SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Failed to recv, header length is less than 0.");
+               goto CATCH;
+       }
+
+       SysLog(NID_IO, "recv - header length = %d", headerLength);
+       SysLog(NID_IO, "recv - header data = %s", header);
+
+       pGIOChannel = g_io_channel_unix_new(clientFd);
+       SysTryCatch(NID_IO, pGIOChannel != null, , E_SYSTEM,    "[E_SYSTEM] Failed to create GIOChannel.");
+
+       g_io_channel_set_encoding(pGIOChannel, NULL, &pGError);
+       g_io_channel_set_flags(pGIOChannel, G_IO_FLAG_NONBLOCK, &pGError);
+
+       g_io_channel_set_close_on_unref(pGIOChannel, TRUE);
+       //clientFd = -1;
+
+       // Handshake with WebApp
+       // check if header of app socket is not for websocket
+       headerData = header;
+       headerType = VerifyHttpHeaderType(headerData, headerLength);
+
+       SysLog(NID_IO, "VerifyHttpHeader, type = %d", headerType);
+
+       if (headerType == WS_NONE)
+       {
+               SysLog(NID_IO, "Unpermitted header type");
+               close(clientFd);
+       }
+
+       // Set the header type
+       gHeaderType = headerType;
+
+
+       // create soup header
+       pSoupHeader = soup_message_headers_new(SOUP_MESSAGE_HEADERS_REQUEST);
+       //soup_headers_parse(header.c_str(), headerLength, pSoupHeader);
+       soup_headers_parse(header, headerLength, pSoupHeader);
+
+       if (headerType == WS_HYBI00)
+       {
+               SysLog(NID_IO, "WS_HYBI00");
+
+               // get third information from http header
+               unsigned int firstInfo = ExtractChallengeNumber(
+                               soup_message_headers_get_one(pSoupHeader, webSocketHeaderKey1));
+               unsigned int secondInfo = ExtractChallengeNumber(
+                               soup_message_headers_get_one(pSoupHeader, webSocketHeaderKey2));
+               unsigned char thirdInfo[8];
+               //char *pThirdInfoPos = const_cast<char*>(header.c_str()) + headerLength - _CHALLENGE_THIRD_INFO_SIZE;
+               char *pThirdInfoPos = const_cast<char*>(header) + headerLength - _CHALLENGE_THIRD_INFO_SIZE;
+               memcpy(thirdInfo, reinterpret_cast<unsigned char*>(pThirdInfoPos), _CHALLENGE_THIRD_INFO_SIZE);
+
+               // make challenge response data for hybi00
+               const std::string response = MakeHybi00Response(firstInfo, secondInfo, thirdInfo);
+               // create response header to be sent to app
+               std::string responseHeader = CreateResponseHeader(clientFd, pSoupHeader, response);
+               // send response header
+               len = send(clientFd, responseHeader.c_str(), responseHeader.size(), 0);
+
+       }
+       else if (headerType == WS_HYBI10)
+       {
+               SysLog(NID_IO, "WS_HYBI10");
+
+               const char* pSecureKeyValue = soup_message_headers_get_one(
+                               pSoupHeader, webSocketHeaderKey);
+
+               std::string secureKey(pSecureKeyValue);
+               secureKey.append(webSocketMagicString);
+
+               // make Sec-WebSocket-Accept data for hybi10
+               const std::string response = MakeHybi10Response(secureKey);
+
+               // create response header to be sent to app
+               std::string responseHeader = CreateResponseHeader(clientFd, pSoupHeader, response);
+
+               // send response header
+               SysLog(NID_IO, "Send responseHeader = %s", responseHeader.c_str());
+               len = send(clientFd, responseHeader.c_str(), responseHeader.size(), 0);
+               if (len < 1)
+               {
+                       SysLog(NID_IO, "errno = %d %s", errno, strerror(errno));
+                       SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Failed to send responseHeader, length is less than 1.");
+                       goto CATCH;
+               }
+       }
+       else
+       {
+               SysLog(NID_IO, "ELSE");
+       }
+
+       if (len == -1)
+       {
+               SysLog(NID_IO, "Failed to send responseHeader");
+               SysLog(NID_IO, "errno = %d %s", errno, strerror(errno));
+               close(clientFd);
+               return false;
+       }
+
+       // Parse and set appId for WebApp
+       {
+               String tempStr;
+               String headerString(header);
+
+               // header = "GET /ipc?src=abcde1234.WebApp&dest=4z6olle215.Dictionary HTTP/1.1^M"
+               StringTokenizer st(headerString, L" /?=&");
+               st.GetNextToken(tempStr); // GET
+               st.GetNextToken(tempStr); // ipc
+               st.GetNextToken(tempStr); // src
+               st.GetNextToken(srcAppId);
+               st.GetNextToken(tempStr); // dest
+               st.GetNextToken(destAppId);
+       }
+
+       // Check the destAppId
+       out = pChannelStub->__pChannelService->IsChannelRegistered(destAppId);
+       SysTryCatch(NID_IO, out, , E_SYSTEM, "[E_SYSTEM] Destination channel is not found.");
+
+       // Set a ClientInfo
+       key = srcAppId;
+       pChannelStub->__pClients->ContainsKey(key, out);
+       if (!out) // first connection request from this client
+       {
+               SysLog(NID_IO, "First Connection of WebApp - AppId = %ls", srcAppId.GetPointer());
+
+               pClientInfo = new (std::nothrow) _ClientInfo();
+
+               pClientInfo->srcAppId = srcAppId;
+               //pClientInfo->srcAppExecName = srcAppExecName;
+               pClientInfo->pChannelStub = pChannelStub;
+               //pClientInfo->clientId = clientFd;
+               pClientInfo->key = key;
+
+               pChannelStub->__pClients->Add(*(new String(key)), *pClientInfo);
+
+               // Stores client info to _ChannelService
+               SysLog(NID_IO, "Register Channel for WebApp");
+
+               pChannelStub->__pChannelService->RegisterChannel(srcAppId, clientFd, WEBAPP_CHANNEL);
+       }
+
+       SysLog(NID_IO, "srcAppId = %ls, destAppId = %ls", srcAppId.GetPointer(), destAppId.GetPointer());
+
+       // Set the callbak
+       pChannelInfo = new (std::nothrow) _ChannelInfo;
+       SysTryCatch(NID_IO, pChannelInfo != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
+
+       pGSource = g_io_create_watch(pGIOChannel, (GIOCondition) (G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP));
+
+       g_source_set_callback(pGSource, (GSourceFunc) OnReadMessage, pChannelInfo, NULL);
+       g_source_attach(pGSource, ((_ChannelWebAppStub*)data)->__pGMainContext);
+
+       pChannelStub->__pClientGSource = pGSource;
+
+
+       // Set a ChannelInfo
+       pChannelInfo->pClientInfo = pClientInfo;
+       pChannelInfo->pGIOChannel = pGIOChannel;
+       pChannelInfo->pGSource = pGSource;
+       pChannelInfo->destAppId = destAppId;
+
+       pClientInfo->channels.push_back(pChannelInfo);
+
+
+       return true;
+
+CATCH:
+       if (pGIOChannel != null)
+       {
+               g_io_channel_unref(pGIOChannel);
+       }
+
+       if (clientFd != -1)
+       {
+               close(clientFd);
+       }
+
+       return true;
+}
+
+gboolean
+_ChannelWebAppStub::OnReadMessage(GIOChannel* source, GIOCondition condition, gpointer data)
+{
+       SysLog(NID_IO, "Callback");
+
+       gboolean ret = FALSE;
+
+       _ChannelInfo* pChannelInfo = (_ChannelInfo*) data;
+       _ClientInfo* pClientInfo = pChannelInfo->pClientInfo;
+       _ChannelWebAppStub* pChannelStub = (_ChannelWebAppStub*) pClientInfo->pChannelStub;
+       ret = pChannelStub->HandleReceivedMessage(source, condition, data);
+
+       return ret;
+}
+
+gboolean
+_ChannelWebAppStub::HandleReceivedMessage(GIOChannel* source, GIOCondition condition, gpointer data)
+{
+       result r = E_SUCCESS;
+       GError* pGError = null;
+       int clientFd = g_io_channel_unix_get_fd(source);
+
+       SysLog(NID_IO, "HandleMessage - client = %d", clientFd);
+
+       _ChannelInfo* pChannelInfo = (_ChannelInfo*) data;
+       _ClientInfo* pClientInfo = pChannelInfo->pClientInfo;
+       _ChannelWebAppStub* pChannelStub = (_ChannelWebAppStub*) pClientInfo->pChannelStub;
+
+       if (condition & G_IO_HUP)
+       {
+               SysLog(NID_IO, "G_IO_HUP - connection closed");
+
+               g_io_channel_shutdown(source, FALSE, &pGError);
+
+               for (unsigned int i = 0; i < pClientInfo->channels.size(); i++)
+               {
+                       if (pChannelInfo == pClientInfo->channels[i])
+                       {
+                               pClientInfo->channels.erase(pClientInfo->channels.begin() + i);
+
+                               // Do not destroy a source in a dispatch callback
+                               // because main loop will do it if the callback return FALSE.
+                               pChannelInfo->destroySource = false;
+                               delete pChannelInfo;
+
+                               break;
+                       }
+               }
+
+               if (pClientInfo->channels.size() == 0)
+               {
+                       SysLog(NID_IO, "All connections of client(%ls) are closed. delete client info", pClientInfo->srcAppId.GetPointer());
+
+                       String key = pClientInfo->srcAppId;
+                       __pClients->Remove(key, false);
+
+                       delete pClientInfo;
+
+                       pChannelStub->__pChannelService->UnregisterChannel(clientFd);
+               }
+
+               return FALSE;
+       }
+       else if (condition & G_IO_IN)
+       {
+               SysLog(NID_IO, "G_IO_IN");
+
+               unique_ptr<char[]> pBuffer(new char[MAX_BUFFER_LENGTH]);
+               int len = recv(clientFd, (char *)pBuffer.get(), MAX_BUFFER_LENGTH, 0);
+               if (len < 0)
+               {
+                       SysLog(NID_IO, "recv error: errno = %d %s", errno, strerror(errno));
+                       SysLog(NID_IO, "headerLength = %d", len);
+                       SysLog(NID_IO, "Recv header = %s", pBuffer.get());
+
+                       SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Failed to recv, length is less than 0.");
+
+                       return FALSE;
+               }
+               else if (len == 0)
+               {
+                       SysLog(NID_IO, "The peer has performed an orderly shutdown, recv = %d", len);
+
+                       g_io_channel_shutdown(source, FALSE, &pGError);
+
+                       for (unsigned int i = 0; i < pClientInfo->channels.size(); i++)
+                       {
+                               if (pChannelInfo == pClientInfo->channels[i])
+                               {
+                                       pClientInfo->channels.erase(pClientInfo->channels.begin() + i);
+
+                                       // Do not destroy a source in a dispatch callback
+                                       // because main loop will do it if the callback return FALSE.
+                                       pChannelInfo->destroySource = false;
+                                       delete pChannelInfo;
+
+                                       break;
+                               }
+                       }
+
+                       if (pClientInfo->channels.size() == 0)
+                       {
+                               SysLog(NID_IO, "All connections of client(%ls) are closed. delete client info", pClientInfo->srcAppId.GetPointer());
+
+                               String key = pClientInfo->srcAppId;
+                               __pClients->Remove(key, false);
+
+                               delete pClientInfo;
+
+                               pChannelStub->__pChannelService->UnregisterChannel(clientFd);
+                       }
+
+                       return FALSE;
+               }
+
+               if (gHeaderType == WS_HYBI00)
+               {
+                       // Not supported because of old websocket protocol
+                       SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Not supported protocol.");
+
+                       return FALSE;
+               }
+               else if (gHeaderType == WS_HYBI10)
+               {
+                       SysLog(NID_IO,"WS_HYBI10 is supported, received data: %s (%d)", pBuffer.get(), len);
+
+                       // Current webkit of tizen support
+                       _WebSocketMessage message;
+                       int ret = 0;
+                       ret = message.ParseHeader(reinterpret_cast<uint8_t*>(pBuffer.get()), len);
+                       SysTryReturn(NID_IO, ret >= 0, FALSE, E_SYSTEM, "[E_SYSTEM] Fail to parse the header!");
+
+                       ret = message.ParsePayload(reinterpret_cast<uint8_t*>(pBuffer.get()), len);
+                       SysTryReturn(NID_IO, ret >= 0, FALSE, E_SYSTEM, "[E_SYSTEM] Fail to parse the payload!");
+
+                       message.ConsoleMessage();
+
+                       // do something for opcode or custom protocol of payload
+                       if (message.m_header.factors.opcode == OPCODE_CONNECTION_CLOSE)
+                       {
+                               SysLog(NID_IO,"OPCODE_CONNECTION_CLOSE with clientFd: %d", clientFd);
+
+                               g_io_channel_shutdown(source, FALSE, &pGError);
+
+                               for (unsigned int i = 0; i < pClientInfo->channels.size(); i++)
+                               {
+                                       if (pChannelInfo == pClientInfo->channels[i])
+                                       {
+                                               pClientInfo->channels.erase(pClientInfo->channels.begin() + i);
+
+                                               // Do not destroy a source in a dispatch callback
+                                               // because main loop will do it if the callback return FALSE.
+                                               pChannelInfo->destroySource = false;
+                                               delete pChannelInfo;
+
+                                               break;
+                                       }
+                               }
+
+                               if (pClientInfo->channels.size() == 0)
+                               {
+                                       SysLog(NID_IO, "All connections of client(%ls) are closed. delete client info", pClientInfo->srcAppId.GetPointer());
+
+                                       String key = pClientInfo->srcAppId;
+                                       __pClients->Remove(key, false);
+
+                                       delete pClientInfo;
+
+                                       pChannelStub->__pChannelService->UnregisterChannel(clientFd);
+                               }
+
+                               return FALSE;
+                       }
+                       else if (message.m_header.factors.opcode == OPCODE_TEXT_MESSAGE)
+                       {
+                               // Parse the data
+                               RequestId reqId = 0;
+
+                               ArrayList list;
+                               list.Construct();
+
+                               list.Add(*(new String((char*)message.m_payload)));
+
+                               SysLog(NID_IO, "srcAppId = %ls, destAppId = %ls", pClientInfo->srcAppId.GetPointer(), pChannelInfo->destAppId.GetPointer());
+
+                               r = pChannelStub->__pChannelService->SendRequest(pClientInfo->srcAppId,
+                                               pChannelInfo->destAppId, list, reqId);
+                               SysTryReturn(NID_IO, !IsFailed(r), FALSE, E_SYSTEM, "[E_SYSTEM] Failed to send request.");
+
+                               list.RemoveAll(true);
+                       }
+                       else
+                       {
+                               // Not yet supported opcode
+                               SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Not supported Opcode.");
+
+                               return FALSE;
+                       }
+               }
+               else
+               {
+                       SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Not supported protocol.");
+
+                       return FALSE;
+               }
+
+       }
+       else
+       {
+               SysLog(NID_IO, "G_IO else");
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+WebSocketType
+_ChannelWebAppStub::VerifyHttpHeaderType(std::string header, int headerLength)
+{
+       // parse http header
+       SoupMessageHeaders* pSoupHeader =
+               soup_message_headers_new(SOUP_MESSAGE_HEADERS_REQUEST);
+       if (!soup_headers_parse(header.c_str(), headerLength, pSoupHeader))
+       {
+               return WS_NONE;
+       }
+
+       WebSocketType headerType;
+       const char* pHeaderValue =
+               soup_message_headers_get_one(pSoupHeader, webSocketHeaderId);
+
+       if (!pHeaderValue)
+       {
+               SysLog(NID_IO, "Not for web socket header.");
+               return WS_NONE;
+       }
+
+       if (strcmp(pHeaderValue, webSocketHeaderIdHybi00) == 0)
+       {
+               headerType = WS_HYBI00;
+       }
+       if (strcmp(pHeaderValue, webSocketHeaderIdHybi10) == 0)
+       {
+               headerType = WS_HYBI10;
+       }
+       else
+       {
+               headerType = WS_NONE;
+       }
+
+       return headerType;
+}
+
+std::string
+_ChannelWebAppStub::CreateResponseHeader(int appSocket, SoupMessageHeaders *header,
+               const std::string& response)
+{
+       std::string responseHeader;
+
+       //if (m_appSockets[appSocket] == WS_HYBI00) {
+       if (gHeaderType == WS_HYBI00)
+       {
+               responseHeader.append("HTTP/1.1 101 WebSocket Protocol Handshake\r\n");
+               responseHeader.append("Upgrade: WebSocket\r\n");
+               responseHeader.append("Connection: Upgrade\r\n");
+               responseHeader.append("Sec-WebSocket-Origin: ");
+               responseHeader.append(soup_message_headers_get_one(header, "Origin"));
+               responseHeader.append("\r\n");
+               responseHeader.append("Sec-WebSocket-Location: ws://");
+               responseHeader.append(soup_message_headers_get_one(header, "Host"));
+               responseHeader.append("\r\n");
+               responseHeader.append("\r\n");
+               responseHeader.append(response.c_str());
+               //} else if (m_appSockets[appSocket] == WS_HYBI10) {
+       }
+       else if (gHeaderType == WS_HYBI10)
+       {
+               responseHeader.append("HTTP/1.1 101 Switching Protocols\r\n");
+               responseHeader.append("Upgrade: websocket\r\n");
+               responseHeader.append("Connection: Upgrade\r\n");
+               responseHeader.append("Sec-WebSocket-Accept: ");
+               responseHeader.append(response.c_str());
+               responseHeader.append("\r\n");
+               responseHeader.append("\r\n");
+               // TODO Sec-WebSocket-Protocol support
+       }
+       else
+       {
+               responseHeader = std::string();
+       }
+
+       return responseHeader;
+}
+
+std::string
+_ChannelWebAppStub::MakeHybi00Response(uint32_t first, uint32_t second, uint8_t* third)
+{
+       SysAssertf(third != null, "The input parameter third should not be null.");
+
+       if (sizeof(third) != _CHALLENGE_NUMBER_SIZE)
+       {
+               SysLog(NID_IO, "Invalid third argument.");
+               return NULL;
+       }
+
+       bool result = false;
+       uint8_t temp[_CHALLENGE_RESPONSE_SIZE];
+       result = AppendChallengeNumber(first, &temp[0]);
+       if (!result)
+       {
+               SysLog(NID_IO, "Failed to set challenge number.");
+               return NULL;
+       }
+
+       result = AppendChallengeNumber(second, &temp[4]);
+       if (!result)
+       {
+               SysLog(NID_IO, "Failed to set challenge number.");
+               return NULL;
+       }
+
+       memcpy(temp + 8, third, _CHALLENGE_THIRD_INFO_SIZE);
+       SysLog(NID_IO,"Challenge Response before md5 : %s", reinterpret_cast<char *>(temp));
+
+       // set MD5 hash
+       unsigned char hash[16];
+       MD5((unsigned char*) temp, _CHALLENGE_RESPONSE_SIZE, hash);
+
+       return std::string(reinterpret_cast<const char*>(hash));
+}
+
+std::string
+_ChannelWebAppStub::MakeHybi10Response(std::string& secureAccept)
+{
+       if (secureAccept.empty())
+       {
+               SysLog(NID_IO, "Invalid argruments");
+               return NULL;
+       }
+
+       unsigned char hash[20];
+       SHA1(reinterpret_cast<const unsigned char*>(secureAccept.c_str()),
+                       secureAccept.size(),
+                       hash);
+
+       return std::string(EncodeBase64(hash, 20));
+}
+
+bool
+_ChannelWebAppStub::AppendChallengeNumber(uint32_t number, unsigned char *response)
+{
+       if (!response)
+       {
+               SysLog(NID_IO, "Invalid response string");
+               return false;
+       }
+
+       // by spec, challenge number should be added as big endian
+       unsigned char* pIdx = response + 3;
+       for (int i = 0; i < 4; i++)
+       {
+               *pIdx = 0xff & number;
+               pIdx--;
+               number >>= 8;
+       }
+
+       return true;
+}
+
+unsigned int
+_ChannelWebAppStub::ExtractChallengeNumber(const char* keyString)
+{
+       if (!keyString)
+       {
+               SysLog(NID_IO, "Invalid secure key");
+               return 0;
+       }
+
+       int space = 0;
+       std::string digits;
+       std::string secureKey(keyString);
+       std::string::iterator it;
+
+       for (it = secureKey.begin(); it < secureKey.end(); it++)
+       {
+               if (*it == ' ')
+               {
+                       space++;
+               }
+               else if ((*it >= '0') && (*it <= '9'))
+               {
+                       digits.insert(digits.end(), 1, *it);
+               }
+       }
+
+       std::istringstream stream(digits);
+       unsigned int numFromDigits = 0;
+       stream >> numFromDigits;
+
+       return space ? (numFromDigits / space) : numFromDigits;
+}
+
+char*
+_ChannelWebAppStub::EncodeBase64(unsigned char *string, int len)
+{
+       BIO* pBmem = null;
+       BIO* pB64 = null;
+       BUF_MEM* pBptr = null;
+
+       pB64 = BIO_new(BIO_f_base64());
+       pBmem = BIO_new(BIO_s_mem());
+       pB64 = BIO_push(pB64, pBmem);
+       BIO_write(pB64, string, len);
+       BIO_flush(pB64);
+       BIO_get_mem_ptr(pB64, &pBptr);
+
+       char* pBuff = (char *)malloc(pBptr->length);
+       SysTryLogReturn(NID_IO, pBuff != NULL, NULL, "The memory is insufficient.");
+       memcpy(pBuff, pBptr->data, pBptr->length-1);
+       pBuff[pBptr->length-1] = 0;
+
+       BIO_free_all(pB64);
+       return pBuff;
+}
+
+bool
+_ChannelWebAppStub::SendResponse(int clientId, const ArrayList& args)
+{
+       unique_ptr<char[]> pStr(_StringConverter::CopyToCharArrayN(*((String*)args.GetAt(0))));
+
+       SysLog(NID_IO, "clientId = %d, data = %s", clientId, pStr.get());
+
+       string response;
+       string payload(pStr.get());
+
+       int respSize = _WebSocketMessage::CreateMessage(payload, response);
+       int ret = send(clientId, response.c_str(), respSize, 0);
+       SysTryLogReturn(NID_IO, ret >= 1, false, "Failed to send data. Length is less than 1. errno = %d %s", errno, strerror(errno));
+
+       SysLog(NID_IO, "response = %s, size = %d", response.c_str(), ret);
+
+       _WebSocketMessage message;
+       ret = message.ParseHeader(reinterpret_cast<uint8_t*>(const_cast<char*>(response.c_str())), respSize);
+       SysTryLogReturn(NID_IO, ret >= 0, false, "ParseHeader error!");
+
+       ret = message.ParsePayload(reinterpret_cast<uint8_t*>(const_cast<char*>(response.c_str())), respSize);
+       SysTryLogReturn(NID_IO, ret >= 0, false, "ParsePayloadr error!");
+
+       message.ConsoleMessage();
+
+       return true;
+}
+
+}}
+
index 5719aca..9dd9b39 100644 (file)
 
 #include <unique_ptr.h>
 
+#include <bundle.h>
+#include <message-port.h>
+
 #include <FBaseStringComparer.h>
 #include <FBaseSysLog.h>
 
 #include "FIo_MessagePortStub.h"
 #include "FIo_MessagePortService.h"
 
-
 using namespace Tizen::Base;
 using namespace Tizen::Base::Collection;
 using namespace Tizen::Io;
 using namespace Tizen::App;
 
-namespace Tizen { namespace Io
-{
+static const char LOCAL_APPID[] = "LOCAL_APPID";
+static const char LOCAL_PORT[] = "LOCAL_PORT";
+static const char TRUSTED_LOCAL[] = "TRUSTED_LOCAL";
+
+static const char REMOTE_APPID[] = "REMOTE_APPID";
+static const char REMOTE_PORT[] = "REMOTE_PORT";
+static const char TRUSTED_REMOTE[] = "TRUSTED_REMOTE";
+static const char TRUSTED_MESSAGE[] = "TRUSTED_MESSAGE";
 
 _MessagePortService::_MessagePortService(void)
        : __pStub(null)
@@ -66,56 +74,68 @@ _MessagePortService::Construct(_MessagePortStub& stub)
        return E_SUCCESS;
 }
 
-result
-_MessagePortService::RegisterMessagePort(const String& appId, const String& port, int clientId, bool isTrusted)
+int
+_MessagePortService::RegisterMessagePort(int clientId, const BundleBuffer& buffer)
 {
-       result r = E_SUCCESS;
-       bool out = false;
-       int id = 0;
+       bundle* b = buffer.b;
+
+       String key = GetKey(buffer);
+       String trusted(bundle_get_val(b, TRUSTED_LOCAL));
+
+       SysLog(NID_IO, "Register a message port: [%ls], client id = %d", key.GetPointer(), clientId);
 
-       String key = GetKey(appId, port);
+       bool out = false;
 
-       if (!isTrusted)
+       if (trusted.Equals(L"FALSE", false))
        {
                __pPorts->ContainsKey(key, out);
-               SysTryReturnResult(NID_IO, !out, E_SYSTEM,  "The port (%ls) has already registered", key.GetPointer());
+               SysTryReturnResult(NID_IO, !out, MESSAGEPORT_ERROR_IO_ERROR,  "The port (%ls) has already registered", key.GetPointer());
 
                __pPorts->Add(key, clientId);
        }
        else
        {
                __pTrustedPorts->ContainsKey(key, out);
-               SysTryReturnResult(NID_IO, !out, E_SYSTEM,  "The trusted port (%ls) has already registered", key.GetPointer());
+               SysTryReturnResult(NID_IO, !out, MESSAGEPORT_ERROR_IO_ERROR,  "The trusted port (%ls) has already registered", key.GetPointer());
 
                __pTrustedPorts->Add(key, clientId);
        }
 
-       return E_SUCCESS;
+       return 0;
 }
 
-result
-_MessagePortService::RequestRemotePort(const AppId& remoteAppId, const String& remotePort, bool isTrusted)
+int
+_MessagePortService::CheckRemotePort(const BundleBuffer& buffer)
 {
-       result r = E_SUCCESS;
-       bool out = false;
-       int id = 0;
+       bundle* b = buffer.b;
+
+       String key = GetKey(buffer, false);
+       String trusted(bundle_get_val(b, TRUSTED_REMOTE));
 
-       String key = GetKey(remoteAppId, remotePort);
+       SysLog(NID_IO, "Check a remote message port: [%ls]", key.GetPointer());
 
-       if (!isTrusted)
+       bool out = false;
+
+       if (trusted.Equals(L"FALSE", false))
        {
                __pPorts->ContainsKey(key, out);
-               SysTryReturnResult(NID_IO, out, E_OBJ_NOT_FOUND,
-                               "The remote message port (%ls) is not found.", key.GetPointer());
+               if (!out)
+               {
+                       SysLogException(NID_IO, E_OBJ_NOT_FOUND, "[E_OBJ_NOT_FOUND] The remote message port [%ls] is not found.", key.GetPointer());
+                       return MESSAGEPORT_ERROR_MESSAGEPORT_NOT_FOUND;
+               }
        }
        else
        {
                __pTrustedPorts->ContainsKey(key, out);
-               SysTryReturnResult(NID_IO, out, E_OBJ_NOT_FOUND,
-                               "The trusted remote message port (%ls) is not found.", key.GetPointer());
+               if (!out)
+               {
+                       SysLogException(NID_IO, E_OBJ_NOT_FOUND, "[E_OBJ_NOT_FOUND] The trusted remote message port [%ls] is not found.", key.GetPointer());
+                       return MESSAGEPORT_ERROR_MESSAGEPORT_NOT_FOUND;
+               }
        }
 
-       return E_SUCCESS;
+       return 0;
 }
 
 result
@@ -170,69 +190,56 @@ _MessagePortService::UnregisterMessagePort(int clientId)
 }
 
 result
-_MessagePortService::SendMessage(const String& dest, const String& destPort,
-                                                               bool isTrusted, const HashMap* pMap)
+_MessagePortService::SendMessage(const BundleBuffer& buffer)
 {
        result r = E_SUCCESS;
-
        int clientId = 0;
-       String key = GetKey(dest, destPort);
 
-       if (!isTrusted)
+       bundle* b = buffer.b;
+
+       String key = GetKey(buffer, false);
+       SysLog(NID_IO, "Sends a message to a remote message port [%ls]", key.GetPointer());
+
+       String trustedMessage(bundle_get_val(b, TRUSTED_MESSAGE));
+       if (trustedMessage.Equals(L"FALSE", false))
        {
-               __pPorts->GetValue(key, clientId);
+               r = __pPorts->GetValue(key, clientId);
        }
        else
        {
-               __pTrustedPorts->GetValue(key, clientId);
+               r = __pTrustedPorts->GetValue(key, clientId);
        }
 
        SysTryReturnResult(NID_IO, r == E_SUCCESS, E_OBJ_NOT_FOUND,
                                "The destination message port is not found.");
 
-       r = __pStub->SendMessage(clientId, destPort, isTrusted, pMap);
+       r = __pStub->SendMessage(clientId, buffer);
        SysTryReturnResult(NID_IO, r == E_SUCCESS, E_SYSTEM, "Failed to send a message");
 
        return E_SUCCESS;
 }
 
-result
-_MessagePortService::SendMessage(const String& src, const String& srcPort, bool isTrustedSrc,
-                                                               const String& dest, const String& destPort, bool isTrustedDest,
-                                                               const HashMap* pMap)
+String 
+_MessagePortService::GetKey(const BundleBuffer& buffer, bool local) const
 {
-       result r = E_SUCCESS;
-       int clientId = 0;
-
-       String key = GetKey(dest, destPort);
+       const char* pAppId = null; 
+       const char* pPortName = null; 
 
-       if (!isTrustedDest)
+       if (local)
        {
-               r = __pPorts->GetValue(key, clientId);
+               pAppId = bundle_get_val(buffer.b, LOCAL_APPID);
+               pPortName = bundle_get_val(buffer.b, LOCAL_PORT);
        }
        else
        {
-               r = __pTrustedPorts->GetValue(key, clientId);
+               pAppId = bundle_get_val(buffer.b, REMOTE_APPID);
+               pPortName = bundle_get_val(buffer.b, REMOTE_PORT);
        }
 
-       SysTryReturnResult(NID_IO, r == E_SUCCESS, E_OBJ_NOT_FOUND,
-                               "The destination message port is not found.");
-
-       r = __pStub->SendMessage(clientId, destPort, isTrustedDest, src, srcPort, isTrustedSrc, pMap);
-       SysTryReturnResult(NID_IO, r == E_SUCCESS, E_SYSTEM, "Failed to send a message");
-
-       return E_SUCCESS;
-}
-
-String 
-_MessagePortService::GetKey(const String& appId, const String& port) const
-{
-       String key(appId);
+       String key(pAppId);
        key.Append(L':');
-       key.Append(port);
+       key.Append(pPortName);
 
        return key;
 }
 
-} } // Tizen::Io
-
index fa05a40..df95596 100644 (file)
  *
  */
 
+#include <message-port-messages.h>
+
+#include <bundle.h>
+
 #include <FBaseSysLog.h>
-#include <FIo_IpcServer.h>
-#include <FIo_MessagePortMessages.h>
 
 #include "FIo_MessagePortStub.h"
 #include "FIo_MessagePortService.h"
@@ -34,8 +36,12 @@ using namespace Tizen::Base::Runtime;
 using namespace Tizen::Io;
 using namespace Tizen::App;
 
-namespace Tizen { namespace Io
+static void 
+ConvertBundleToMap(const char *pKey, const int type, const bundle_keyval_t *pVal, void *pData)
 {
+       SysLog(NID_IO, "CB key = %s", pKey);
+
+}
 
 _MessagePortStub::_MessagePortStub(void)
        : __pIpcServer(null)
@@ -55,12 +61,10 @@ _MessagePortStub::Construct(void)
        SysAssertf(__pIpcServer == null, "Already constructed. Calling Construct() twice or more on a same instance is not allowed for this class.");
 
        result r = E_SUCCESS;
-       _IpcServer* pIpcServer = null;
-
-       pIpcServer = new (std::nothrow) _IpcServer;
+       IpcServer* pIpcServer = new (std::nothrow) IpcServer;
        SysTryReturnResult(NID_IO, pIpcServer != null, E_OUT_OF_MEMORY, "Not enough memory.");
 
-       r = pIpcServer->Construct("osp.io.ipcserver.messageportmanager", *this, false);
+       r = pIpcServer->Construct("message-port-server", *this, false);
        SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to create IPC server(MessagePort)", GetErrorMessage(r));
 
        __pIpcServer = pIpcServer;
@@ -80,153 +84,87 @@ _MessagePortStub::SetMessagePortService(_MessagePortService& service)
 }
 
 bool
-_MessagePortStub::OnRegisterMessagePort(const String& appId, const String& port, bool isTrusted, int* pResult)
+_MessagePortStub::OnRegisterMessagePort(const BundleBuffer& buffer, int* pResult)
 {
        SysAssertf(__pService != null, "Message port service has not been initialized.\n");
 
        int clientId = __pIpcServer->GetClientId();
 
-       SysLog(NID_IO, "Register a message port: [%ls:%ls], client id = %d", appId.GetPointer(), port.GetPointer(), clientId);
+       *pResult = __pService->RegisterMessagePort(clientId, buffer);
 
-       *pResult = __pService->RegisterMessagePort(appId, port, clientId, isTrusted);
+       bundle_free(buffer.b);
 
        return true;
 }
 
 bool
-_MessagePortStub::OnRequestRemotePort(const AppId& remoteAppId, const String& remotePort, bool isTrusted, int* pResult)
+_MessagePortStub::OnCheckRemotePort(const BundleBuffer& buffer, int* pResult)
 {
        SysAssertf(__pService != null, "Message port service has not been initialized.\n");
 
-       int clientId = __pIpcServer->GetClientId();
+       *pResult = __pService->CheckRemotePort(buffer);
 
-       SysLog(NID_IO, "Request a remote message port: [%ls:%ls]", remoteAppId.GetPointer(), remotePort.GetPointer());
-
-       *pResult = __pService->RequestRemotePort(remoteAppId, remotePort, isTrusted);
+       bundle_free(buffer.b);
 
        return true;
 }
 
 bool
-_MessagePortStub::OnSendMessage(const String& dest, const String& destPort,
-                                                               bool isTrusted, const HashMap& map,
-                                                               int* pResult)
+_MessagePortStub::OnSendMessage(const BundleBuffer& buffer, int* pResult)
 {
        SysAssertf(__pService != null, "MessagePort service has not been initialized.\n");
 
-       SysLog(NID_IO, "Message is sent to [%ls:%ls]", dest.GetPointer(), destPort.GetPointer());
-
-       if (!isTrusted)
-       {
-               *pResult = __pService->SendMessage(dest, destPort, false, &map);
-       }
-       else
-       {
-               *pResult = __pService->SendMessage(dest, destPort, true, &map);
-       }
+       *pResult = __pService->SendMessage(buffer);
 
-       const_cast<HashMap*>(&map)->RemoveAll(true);
+       bundle_free(buffer.b);
 
        return true;
 }
 
-bool
-_MessagePortStub::OnSendBidirMessage(const String& src, const String& srcPort, bool isTrusted,
-                                                               const String& dest, const String& destPort,
-                                                               const HashMap& map, int* pResult)
-{
-       SysAssertf(__pService != null, "MessagePort service has not been initialized.\n");
-
-       SysLog(NID_IO, "[%ls:%ls] sends a message to [%ls:%ls]", src.GetPointer(), srcPort.GetPointer(), dest.GetPointer(), destPort.GetPointer());
-
-       *pResult = __pService->SendMessage(src, srcPort, isTrusted, dest, destPort, false, &map);
-
-       const_cast<HashMap*>(&map)->RemoveAll(true);
-
-       return true;
-}
-
-bool
-_MessagePortStub::OnSendTrustedBidirMessage(const String& src, const String& srcPort, bool isTrusted,
-                                                               const String& dest, const String& destPort,
-                                                               const HashMap& map, int* pResult)
-{
-       SysAssertf(__pService != null, "MessagePort service has not been initialized.\n");
-
-       SysLog(NID_IO, "[%ls:%ls] sends a message to [%ls:%ls]", src.GetPointer(), srcPort.GetPointer(), dest.GetPointer(), destPort.GetPointer());
-
-       *pResult = __pService->SendMessage(src, srcPort, isTrusted, dest, destPort, true, &map);
-
-       const_cast<HashMap*>(&map)->RemoveAll(true);
-
-       return true;
-}
-
-result
-_MessagePortStub::SendMessage(int clientId, const String& destPort, bool isTrusted, const HashMap* pMap)
-{
-       SysAssertf(__pService != null, "MessagePort service has not been initialized.\n");
-
-       SysLog(NID_IO, "Sends a message to port [%ls]", destPort.GetPointer());
-
-       if (pMap != null)
-       {
-               result r = __pIpcServer->SendResponse(clientId, new MessagePortService_sendMessageAsync(destPort, isTrusted, *pMap));
-               SysTryReturnResult(NID_IO, r == E_SUCCESS, r, "Failed to send a response message.");
-       }
-
-       return E_SUCCESS;
-}
-
 result
-_MessagePortStub::SendMessage(int clientId, const String& destPort, bool isTrustedDest, const String& src, const String& srcPort, bool isTrustedSrc, const HashMap* pMap)
+_MessagePortStub::SendMessage(int clientId, const BundleBuffer& buffer)
 {
        SysAssertf(__pService != null, "MessagePort service has not been initialized.\n");
 
-       SysLog(NID_IO, "[%ls:%ls] sends a message to port [%ls]", src.GetPointer(), srcPort.GetPointer(), destPort.GetPointer());
+       result r = __pIpcServer->SendResponse(clientId, new MessagePort_sendMessageAsync(buffer));
 
-       if (pMap != null)
-       {
-               result r = __pIpcServer->SendResponse(clientId, new MessagePortService_sendBidirMessageAsync(destPort, isTrustedDest, src, srcPort, isTrustedSrc, *pMap));
-               SysTryReturnResult(NID_IO, r == E_SUCCESS, r, "Failed to send a response message.");
-       }
+       SysTryReturnResult(NID_IO, r == E_SUCCESS, r, "Failed to send a response message.");
 
        return E_SUCCESS;
-
 }
 
 void
-_MessagePortStub::OnIpcRequestReceived(_IpcServer& server, const IPC::Message& message)
+_MessagePortStub::OnIpcRequestReceived(IpcServer& server, const IPC::Message& message)
 {
+       SysLog(NID_IO, "Message received, type %d", message.type());
+
        IPC_BEGIN_MESSAGE_MAP(_MessagePortStub, message)
-       IPC_MESSAGE_HANDLER_EX(MessagePortService_register, &server, OnRegisterMessagePort)
-       IPC_MESSAGE_HANDLER_EX(MessagePortService_requestRemotePort, &server, OnRequestRemotePort)
-       IPC_MESSAGE_HANDLER_EX(MessagePortService_sendMessage, &server, OnSendMessage)
-       IPC_MESSAGE_HANDLER_EX(MessagePortService_sendBidirMessage, &server, OnSendBidirMessage)
-       IPC_MESSAGE_HANDLER_EX(MessagePortService_sendTrustedBidirMessage, &server, OnSendTrustedBidirMessage)
+       IPC_MESSAGE_HANDLER_EX(MessagePort_registerPort, &server, OnRegisterMessagePort)
+       IPC_MESSAGE_HANDLER_EX(MessagePort_checkRemotePort, &server, OnCheckRemotePort)
+       IPC_MESSAGE_HANDLER_EX(MessagePort_sendMessage, &server, OnSendMessage)
        IPC_END_MESSAGE_MAP_EX()
 }
 
 void
-_MessagePortStub::OnIpcServerStarted(const _IpcServer& server)
+_MessagePortStub::OnIpcServerStarted(const IpcServer& server)
 {
 
 }
 
 void
-_MessagePortStub::OnIpcServerStopped(const _IpcServer& server)
+_MessagePortStub::OnIpcServerStopped(const IpcServer& server)
 {
 
 }
 
 void
-_MessagePortStub::OnIpcClientConnected(const _IpcServer& server, int clientId)
+_MessagePortStub::OnIpcClientConnected(const IpcServer& server, int clientId)
 {
-
+       SysLog(NID_IO, "Ipc connected");
 }
 
 void
-_MessagePortStub::OnIpcClientDisconnected(const _IpcServer& server, int clientId)
+_MessagePortStub::OnIpcClientDisconnected(const IpcServer& server, int clientId)
 {
        SysAssertf(__pService != null, "Channel service has not been initialized.\n");
        SysLog(NID_IO, "Unregister - clientId =  %d", clientId);
@@ -234,5 +172,3 @@ _MessagePortStub::OnIpcClientDisconnected(const _IpcServer& server, int clientId
        __pService->UnregisterMessagePort(clientId);
 }
 
-} } // Tizen::Io
-
diff --git a/src/IpcServer.cpp b/src/IpcServer.cpp
new file mode 100644 (file)
index 0000000..5c19df2
--- /dev/null
@@ -0,0 +1,810 @@
+//
+// Open Service Platform
+// Copyright (c) 2012 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+/**
+ * @file  FIo_IpcServer.cpp
+ * @brief This is the implementation file for the IpcServer class.
+ *
+ */
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <cerrno>
+#include <iostream>
+#include <new>
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+
+#include <sys/smack.h>
+
+#include <ipc/ipc_message.h>
+
+#include <FBaseRtMutex.h>
+#include <FBaseSysLog.h>
+#include <FBase_StringConverter.h>
+#include <FBaseRt_EventDispatcher.h>
+
+#include "IIpcServerEventListener.h"
+#include "IpcServer.h"
+
+using namespace std;
+using namespace IPC;
+
+using namespace Tizen::Base;
+using namespace Tizen::Base::Runtime;
+using namespace Tizen::App;
+
+IpcServer::_ChannelInfo::_ChannelInfo(void)
+       : pClientInfo(null)
+       , pGIOChannel(null)
+       , pGSource(null)
+       , destroySource(true)
+{
+
+}
+
+IpcServer::_ChannelInfo::~_ChannelInfo(void)
+{
+       if (pGIOChannel != null)
+       {
+               g_io_channel_unref(pGIOChannel);
+       }
+
+       if (pGSource != null)
+       {
+               if (destroySource)
+               {
+                       g_source_destroy(pGSource);
+               }
+
+               g_source_unref(pGSource);
+       }
+}
+
+IpcServer::_ClientInfo::_ClientInfo(void)
+       : clientId(-1)
+       , pIpcServer(null)
+       , pReverseChannel(null)
+{
+
+}
+
+IpcServer::_ClientInfo::~_ClientInfo(void)
+{
+       if (pReverseChannel != null)
+       {
+               g_io_channel_unref(pReverseChannel);
+       }
+
+       channels.clear();
+}
+
+IpcServer::IpcServer(void)
+       : __runOnCallerThread(false)
+       , __pEventDispatcher(null)
+       , __pListener(null)
+       , __handlerThread(0)
+       , __pHandlerGMainContext(null)
+       , __pHandlerGMainLoop(null)
+       , __pConnectGSource(null)
+       , __pCurrentChannel(null)
+       , __pCurrentClientInfo(null)
+{
+       __messageBuffer[0] = '\0';
+}
+
+
+IpcServer::~IpcServer(void)
+{
+       if (__pConnectGSource != null)
+       {
+               g_source_destroy(__pConnectGSource);
+               g_source_unref(__pConnectGSource);
+               __pConnectGSource = null;
+       }
+
+       if (!__runOnCallerThread)
+       {
+               if (__pEventDispatcher)
+               {
+                       delete __pEventDispatcher;
+                       __pEventDispatcher = null;
+               }
+
+               if (__pHandlerGMainLoop)
+               {
+                       g_main_loop_unref(__pHandlerGMainLoop);
+                       __pHandlerGMainLoop = null;
+               }
+
+               if (__pHandlerGMainContext)
+               {
+                       g_main_context_unref(__pHandlerGMainContext);
+                       __pHandlerGMainContext = null;
+               }
+       }
+
+       // clean-up clients
+       __clients.clear();
+}
+
+result
+IpcServer::Construct(const String& name, const IIpcServerEventListener& listener, bool runOnCallerThread)
+{
+       result r = E_SUCCESS;
+
+       GIOChannel* pGIOChannel = null;
+       GSource* pGSource = null;
+
+       struct sockaddr_un serverAddress;
+       int serverSocket = -1;
+       int serverLen = 0;
+       int ret = 0;
+       std::string socketName;
+       char* pName = null;
+       size_t socketNameLength = 0;
+
+       __name = name;
+       __pListener = const_cast <IIpcServerEventListener*>(&listener);
+       __runOnCallerThread = runOnCallerThread;
+
+       pName = _StringConverter::CopyToCharArrayN(name);
+       SysTryReturnResult(NID_IO, pName != null, E_OUT_OF_MEMORY, "Not enough memory");
+
+       socketName.append("/tmp/");
+       socketName.append(pName);
+
+       delete[] pName;
+
+       socketNameLength = socketName.size() + 1;
+       SysTryReturnResult(NID_IO, socketNameLength < 108, E_INVALID_ARG, "Server name is too long");
+
+       if (!__runOnCallerThread)
+       {
+               __pHandlerGMainContext = g_main_context_new();
+               __pHandlerGMainLoop = g_main_loop_new(__pHandlerGMainContext, FALSE);
+
+       }
+       else
+       {
+               __pHandlerGMainContext = g_main_context_get_thread_default();
+               if (__pHandlerGMainContext == null) // is global?
+               {
+                       __pHandlerGMainContext = g_main_context_default();
+                       if (__pHandlerGMainContext == null)
+                       {
+                               return E_SYSTEM;
+                       }
+               }
+       }
+
+       ret = unlink(socketName.c_str());
+       SysTryLog(NID_IO, ret == 0, "Unlink a socket has failed.. but it is not a problem.");
+
+       serverSocket = socket(AF_UNIX, SOCK_STREAM, 0);
+       SysTryReturnResult(NID_IO, serverSocket != -1, E_SYSTEM, "Failed to create a socket.");
+
+       // SMACK (Add a * label to socket)
+       if(smack_fsetlabel(serverSocket, "@", SMACK_LABEL_IPOUT) != 0)
+       {
+               SysTryCatch(NID_IO, errno == EOPNOTSUPP, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] SMACK labeling failed");
+               SysLog(NID_IO, "Kernel doesn't have Smack.");
+       }
+
+       if(smack_fsetlabel(serverSocket, "*", SMACK_LABEL_IPIN) != 0)
+       {
+               SysTryCatch(NID_IO, errno == EOPNOTSUPP, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] SMACK labeling failed");
+               SysLog(NID_IO, "Kernel doesn't have Smack.");
+       }
+
+       bzero(&serverAddress, sizeof(serverAddress));
+       serverAddress.sun_family = AF_UNIX;
+       strncpy(serverAddress.sun_path, socketName.c_str(), socketNameLength);
+       serverLen = sizeof(serverAddress);
+
+       ret = bind(serverSocket, (const struct sockaddr*) &serverAddress, serverLen);
+       SysTryCatch(NID_IO, ret != -1, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to bind a socket(%d, %s): %s", serverSocket,
+                          socketName.c_str(), strerror(errno));
+
+       ret = chmod(socketName.c_str(), 0666);
+       SysTryCatch(NID_IO, ret == 0, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to change permission of a socket(%d, %s): %s", serverSocket,
+                          socketName.c_str(), strerror(errno));
+
+       listen(serverSocket, 15);
+
+       pGIOChannel = g_io_channel_unix_new(serverSocket);
+       SysTryCatch(NID_IO, pGIOChannel != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Not enough memory.");
+
+       // socket will be closed when pGIOChannel is deleted.
+       g_io_channel_set_close_on_unref(pGIOChannel, TRUE);
+       serverSocket = -1;
+
+       pGSource = g_io_create_watch(pGIOChannel, (GIOCondition) (G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP));
+       SysTryCatch(NID_IO, pGSource != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
+                          "[E_OUT_OF_MEMORY] Failed to create watch for socket.");
+
+       // channel will be delete when pGSource is deleted.
+       g_io_channel_unref(pGIOChannel);
+       pGIOChannel = null;
+
+       g_source_set_callback(pGSource, (GSourceFunc) OnConnectionRequest, this, NULL);
+       g_source_attach(pGSource, __pHandlerGMainContext);
+
+       if (__runOnCallerThread)
+       {
+               __pListener->OnIpcServerStarted(*this);
+       }
+       else
+       {
+               ret = pthread_create(&__handlerThread, null, &ThreadProc, (void*) this);
+               SysTryCatch(NID_IO, ret == 0, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to an IPC thread");
+       }
+
+       __pConnectGSource = pGSource;
+
+       return E_SUCCESS;
+
+CATCH:
+       if (pGIOChannel != null)
+       {
+               g_io_channel_unref(pGIOChannel);
+       }
+
+       if (serverSocket != -1)
+       {
+               close(serverSocket);
+       }
+
+       if (runOnCallerThread && __pHandlerGMainContext)
+       {
+               g_main_context_unref(__pHandlerGMainContext);
+               __pHandlerGMainContext = null;
+       }
+
+       return r;
+}
+
+struct HelloMessage
+{
+       int pid;
+       bool reverse;  // true if the connection is for reverse message
+       char appId[256];
+};
+
+gboolean
+IpcServer::OnConnectionRequest(GIOChannel* source, GIOCondition condition, gpointer data)
+{
+       IpcServer* pIpcServer = (IpcServer*) data;
+       GError* pGError = null;
+       HelloMessage helloMessage;
+       _ClientInfo* pClientInfo = null;
+       _ChannelInfo* pChannelInfo = null;
+       GSource* pGSource = null;
+       GIOChannel* pChannel = null;
+
+       int server = -1;
+       int client = -1;
+       struct sockaddr_un clientAddress;
+       socklen_t clientLen = sizeof(clientAddress);
+
+       SysAssertf(pIpcServer != null, "Not yet constructed. Construct() should be called before use.\n");
+       SysAssertf(pIpcServer->__pListener != null, "Listener is null.\n");
+
+       server = g_io_channel_unix_get_fd(source);
+
+       client = accept(server, (struct sockaddr*) &clientAddress, &clientLen);
+       SysTryCatch(NID_IO, client != -1, , E_SYSTEM, "[E_SYSTEM] Accept failed.");
+
+       read(client, &helloMessage, sizeof(helloMessage));
+       helloMessage.appId[255] = '\0';
+
+       pChannel = g_io_channel_unix_new(client);
+       SysTryCatch(NID_IO, pChannel != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Not enough memory.");
+
+       g_io_channel_set_encoding(pChannel, NULL, &pGError);
+       g_io_channel_set_flags(pChannel, G_IO_FLAG_NONBLOCK, &pGError);
+
+       g_io_channel_set_close_on_unref(pChannel, TRUE);
+       client = -1;
+
+       pClientInfo = pIpcServer->__clients[helloMessage.pid];
+       if (pClientInfo == null) // first connection request from this client
+       {
+               pClientInfo = new (std::nothrow) _ClientInfo;
+               SysTryCatch(NID_IO, pClientInfo != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Not enough memory.");
+
+               pClientInfo->pIpcServer = pIpcServer;
+               pClientInfo->clientId = helloMessage.pid;
+               pClientInfo->appId.Append((wchar_t*) helloMessage.appId);
+               pClientInfo->pReverseChannel = null;
+
+               pIpcServer->__clients[helloMessage.pid] = pClientInfo;
+
+               pIpcServer->__pCurrentClientInfo = pClientInfo;
+               pIpcServer->__pListener->OnIpcClientConnected(*pIpcServer, helloMessage.pid);
+               pIpcServer->__pCurrentClientInfo = null;
+       }
+
+       if (helloMessage.reverse)
+       {
+               pClientInfo->pReverseChannel = pChannel;
+       }
+       else
+       {
+               pChannelInfo = new (std::nothrow) _ChannelInfo;
+               SysTryCatch(NID_IO, pChannelInfo != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Not enough memory.");
+
+               pGSource = g_io_create_watch(pChannel, (GIOCondition) (G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP));
+               g_source_set_callback(pGSource, (GSourceFunc) OnReadMessage, pChannelInfo, NULL);
+               g_source_attach(pGSource, pIpcServer->__pHandlerGMainContext);
+
+               pChannelInfo->pClientInfo = pClientInfo;
+               pChannelInfo->pGIOChannel = pChannel;
+               pChannelInfo->pGSource = pGSource;
+
+               pClientInfo->channels.push_back(pChannelInfo);
+       }
+
+       return true;
+
+CATCH:
+       if (pChannel != null)
+       {
+               g_io_channel_unref(pChannel);
+       }
+
+       if (client != -1)
+       {
+               close(client);
+       }
+
+       return true;
+}
+
+int
+IpcServer::GetClientId(void) const
+{
+       if (__pCurrentClientInfo)
+       {
+               return __pCurrentClientInfo->clientId;
+       }
+
+       return -1;
+}
+
+int
+IpcServer::GetClientProcessId(void) const
+{
+       if (__pCurrentClientInfo)
+       {
+               return __pCurrentClientInfo->clientId;
+       }
+
+       return -1;
+}
+
+String
+IpcServer::GetClientAppId(void) const
+{
+       static String nullString;
+
+       if (__pCurrentClientInfo)
+       {
+               return __pCurrentClientInfo->appId;
+       }
+
+       return nullString;
+}
+
+String
+IpcServer::GetClientAppExecutableName(void) const
+{
+       static String nullString;
+
+       //if (__pCurrentClientInfo)
+       {
+               //return __pCurrentClientInfo->appExecutableName;
+       }
+
+       return nullString;
+}
+
+AppId
+IpcServer::GetClientApplicationId(void) const
+{
+       static String nullString;
+
+       if (__pCurrentClientInfo)
+       {
+               return __pCurrentClientInfo->appId;
+       }
+
+       return nullString;
+}
+
+gboolean
+IpcServer::HandleReceivedMessage(GIOChannel* source, GIOCondition condition, gpointer data)
+{
+       GError* pGError = NULL;
+       GIOStatus status;
+       IPC::Message* pMessage = NULL;
+       _ChannelInfo* pChannelInfo = (_ChannelInfo*) data;
+       _ClientInfo* pClientInfo = pChannelInfo->pClientInfo;
+
+       if (condition & G_IO_HUP)
+       {
+               SysLog(NID_IO, "Connection closed");
+               int clientId = pClientInfo->clientId;
+
+               g_io_channel_shutdown(source, FALSE, &pGError);
+
+               for (unsigned int i = 0; i < pClientInfo->channels.size(); i++)
+               {
+                       if (pChannelInfo == pClientInfo->channels[i])
+                       {
+                               pClientInfo->channels.erase(pClientInfo->channels.begin() + i);
+
+                               // Do not destroy a source in a dispatch callback
+                               // because main loop will do it if the callback return FALSE.
+                               pChannelInfo->destroySource = false;
+                               delete pChannelInfo;
+
+                               break;
+                       }
+               }
+
+               if (pClientInfo->channels.size() == 0)
+               {
+                       SysLog(NID_IO, "All connections of client(%d) are closed. delete client info", clientId);
+
+                       __pListener->OnIpcClientDisconnected(*this, clientId);
+
+                       __clients[clientId] = null;
+
+                       delete pClientInfo;
+               }
+
+               return FALSE;
+       }
+       else if (condition & G_IO_IN)
+       {
+               gsize readSize = 0;
+               const char* pStart = NULL;
+               const char* pEnd = NULL;
+               const char* pEndOfMessage = NULL;
+
+               while (true)
+               {
+                       pGError = null;
+                       status = g_io_channel_read_chars(source, (char*) __messageBuffer, __MAX_MESSAGE_BUFFER_SIZE, &readSize, &pGError);
+                       if (status != G_IO_STATUS_NORMAL)
+                       {
+                               if (status == G_IO_STATUS_EOF || status == G_IO_STATUS_ERROR)
+                               {
+                                       if (status == G_IO_STATUS_EOF)
+                                       {
+                                               SysLog(NID_IO, "G_IO_STATUS_EOF, the connection is closed.");
+                                       }
+                                       else
+                                       {
+                                               SysLog(NID_IO, "G_IO_STATUS_ERROR, the connection is closed. ");
+                                       }
+
+                                       pGError = null;
+                                       g_io_channel_shutdown(source, FALSE, &pGError);
+
+                                       int clientId = pClientInfo->clientId;
+
+                                       for (unsigned int i = 0; i < pClientInfo->channels.size(); i++)
+                                       {
+                                               if (pChannelInfo == pClientInfo->channels[i])
+                                               {
+                                                       pClientInfo->channels.erase(pClientInfo->channels.begin() + i);
+
+                                                       pChannelInfo->destroySource = false;
+                                                       delete pChannelInfo;
+                                                       break;
+                                               }
+                                       }
+
+                                       if (pClientInfo->channels.size() == 0)
+                                       {
+                                               SysLog(NID_IO, "All connections of client(%d) are closed normally by the client.", clientId);
+
+                                               if (__pListener)
+                                               {
+                                                       __pListener->OnIpcClientDisconnected(*this, clientId);
+                                               }
+
+                                               __clients[clientId] = null;
+
+                                               delete pClientInfo;
+                                       }
+
+                                       return FALSE;
+                               }
+                       }
+
+                       if (readSize == 0)
+                       {
+                               break;
+                       }
+
+                       if (__pending.empty())
+                       {
+                               pStart = __messageBuffer;
+                               pEnd = pStart + readSize;
+                       }
+                       else
+                       {
+                               __pending.append(__messageBuffer, readSize);
+                               pStart = __pending.data();
+                               pEnd = pStart + __pending.size();
+                       }
+
+                       while (true)
+                       {
+                               pEndOfMessage = IPC::Message::FindNext(pStart, pEnd);
+                               if (pEndOfMessage == NULL)
+                               {
+                                       __pending.assign(pStart, pEnd - pStart);
+                                       break;
+                               }
+
+                               pMessage = new (std::nothrow) IPC::Message(pStart, pEndOfMessage - pStart);
+                               SysTryReturn(NID_IO, pMessage != null, FALSE, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
+
+                               __pCurrentChannel = source;
+
+                               if (__pListener)
+                               {
+                                       __pListener->OnIpcRequestReceived(*this, *pMessage);
+                               }
+
+                               delete pMessage;
+
+                               __pCurrentChannel = NULL;
+
+                               pStart = pEndOfMessage;
+                       }
+               }
+       }
+       else
+       {
+               // empty statement
+       }
+
+       return TRUE;
+}
+
+gboolean
+IpcServer::OnReadMessage(GIOChannel* source, GIOCondition condition, gpointer data)
+{
+       gboolean ret = FALSE;
+       _ChannelInfo* pChannelInfo = (_ChannelInfo*) data;
+       _ClientInfo* pClientInfo = pChannelInfo->pClientInfo;
+       IpcServer* pIpcServer = (IpcServer*) pClientInfo->pIpcServer;
+
+       pIpcServer->__pCurrentClientInfo = pClientInfo;
+       ret = pIpcServer->HandleReceivedMessage(source, condition, data);
+       pIpcServer->__pCurrentClientInfo = null;
+
+       return ret;
+}
+
+void*
+IpcServer::ThreadProc(void* pParam)
+{
+       IpcServer* pIpcServer = (IpcServer*) pParam;
+       if (pIpcServer != NULL)
+       {
+               pIpcServer->Run(NULL);
+       }
+
+       return NULL;
+}
+
+void
+IpcServer::Run(void* pParam)
+{
+       result r = E_SUCCESS;
+
+       if (__pListener == null)
+       {
+               return;
+       }
+
+       __pEventDispatcher = new (std::nothrow) _EventDispatcher;
+       SysTryReturnVoidResult(NID_IO, __pEventDispatcher != null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
+
+       r = __pEventDispatcher->Construct(__pHandlerGMainContext);
+       if (IsFailed(r))
+       {
+               delete __pEventDispatcher;
+               __pEventDispatcher = null;
+       }
+
+       __pListener->OnIpcServerStarted(*this);
+
+       g_main_loop_run(__pHandlerGMainLoop);
+
+       __pListener->OnIpcServerStopped(*this);
+}
+
+result
+IpcServer::Start(void)
+{
+       return E_SUCCESS;
+}
+
+String
+IpcServer::GetName(void) const
+{
+       return __name;
+}
+
+result
+IpcServer::Stop(void)
+{
+       result r = E_SUCCESS;
+       int ret = 0;
+
+       SysTryReturnResult(NID_IO, __pListener != null, E_SYSTEM, "Listener is null.");
+
+       if (!__runOnCallerThread)
+       {
+               pthread_t self = pthread_self();
+
+               if (__pHandlerGMainLoop)
+               {
+                       g_main_loop_quit(__pHandlerGMainLoop);
+               }
+
+               if (__handlerThread != self)
+               {
+                       ret = pthread_join(__handlerThread, null);
+                       SysTryLog(NID_IO, ret == 0, "Join an IPC thread returns an error");
+               }
+       }
+       else
+       {
+               __pListener->OnIpcServerStopped(*this);
+       }
+
+       return r;
+}
+
+bool
+IpcServer::Send(IPC::Message* msg)
+{
+       gsize remain = 0;
+       gsize written = 0;
+       char* pData = NULL;
+       GError* pGError = NULL;
+
+
+       pData = (char*) msg->data();
+       remain = msg->size();
+
+       if (msg->is_reply())
+       {
+               while (remain > 0)
+               {
+                       pGError = NULL;
+                       g_io_channel_write_chars(__pCurrentChannel, (char*) pData, remain, &written, &pGError);
+
+                       remain -= written;
+                       pData += written;
+               }
+
+               g_io_channel_flush(__pCurrentChannel, &pGError);
+       }
+       else
+       {
+               // empty statement;
+       }
+
+       return true;
+}
+
+result
+IpcServer::SendResponse(int client, IPC::Message* pMessage)
+{
+       result r = E_SUCCESS;
+       gsize remain = 0;
+       gsize written = 0;
+       char* pData = null;
+       GError* pGError = null;
+       _ClientInfo* pClientInfo = null;
+
+       SysTryReturn(NID_IO, client >= 0 && pMessage != null, false, E_INVALID_ARG,
+                               "[E_INVALID_ARG] pMessage(0x%x) is null or clinet(%d) < 0", pMessage,
+                               client);
+       SysTryCatch(NID_IO, !pMessage->is_sync(), r = E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] Can't send sync. messagee.");
+
+       pClientInfo = __clients[client];
+       SysTryCatch(NID_IO, pClientInfo != null, r = E_INVALID_ARG, E_INVALID_ARG,
+                          "[E_INVALID_ARG] client(%d) has not been registered.",
+                          client);
+
+       pData = (char*) pMessage->data();
+       remain = pMessage->size();
+
+       while (remain > 0)
+       {
+               pGError = NULL;
+               g_io_channel_write_chars(pClientInfo->pReverseChannel, (char*) pData, remain, &written, &pGError);
+               SysTryCatch(NID_IO, pGError == null, , E_SYSTEM, "[E_SYSTEM] Error occurred during writing message to socket.");
+
+               remain -= written;
+               pData += written;
+       }
+
+       g_io_channel_flush(pClientInfo->pReverseChannel, &pGError);
+
+       delete pMessage;
+
+       return E_SUCCESS;
+
+CATCH:
+       delete pMessage;
+       return r;
+}
+
+result
+IpcServer::SendResponse(int client, const IPC::Message& message)
+{
+       result r = E_SUCCESS;
+       gsize remain = 0;
+       gsize written = 0;
+       char* pData = null;
+       GError* pGError = null;
+       _ClientInfo* pClientInfo = null;
+
+       SysTryReturn(NID_IO, client >= 0, false, E_INVALID_ARG, "[E_INVALID_ARG] clinet(%d) < 0", client);
+       SysTryCatch(NID_IO, !message.is_sync(), r = E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] Can't send sync. messagee.");
+
+       pClientInfo = __clients[client];
+       SysTryCatch(NID_IO, pClientInfo != null, r = E_INVALID_ARG, E_INVALID_ARG,
+                          "[E_INVALID_ARG] client(%d) has not been registered.",
+                          client);
+
+       pData = (char*) message.data();
+       remain = message.size();
+
+       while (remain > 0)
+       {
+               pGError = NULL;
+               g_io_channel_write_chars(pClientInfo->pReverseChannel, (char*) pData, remain, &written, &pGError);
+               SysTryCatch(NID_IO, pGError == null, , E_SYSTEM, "[E_SYSTEM] Error occurred during writing message to socket.");
+
+               remain -= written;
+               pData += written;
+       }
+
+       g_io_channel_flush(pClientInfo->pReverseChannel, &pGError);
+
+       return E_SUCCESS;
+
+CATCH:
+       return r;
+}