From: Jinkun Jang Date: Fri, 15 Mar 2013 16:16:39 +0000 (+0900) Subject: merge with master X-Git-Tag: 2.1b_release~15 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fframework%2Fnative%2Fchannel-service.git;a=commitdiff_plain;h=c236281dcb2c8d86b365ca660de5a394d315c612 merge with master --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ee79a5..5556a4e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/inc/ChannelService.h b/inc/ChannelService.h index 3a4b7b6..1bb2439 100644 --- a/inc/ChannelService.h +++ b/inc/ChannelService.h @@ -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 index 0000000..585c6ed --- /dev/null +++ b/inc/FIo_ChannelCAppStub.h @@ -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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +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 channels; /**< the set of channels associated with a client */ + Tizen::Base::String appId; + //Tizen::Base::String appExecutableName; + }; + + GMainContext* __pGMainContext; + + GSource* __pConnectGSource; + + std::map __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 index 0000000..d04cf30 --- /dev/null +++ b/inc/FIo_ChannelService.h @@ -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 + +#include +#include +#include +#include +#include +#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 + { + public: + virtual int GetHashCode(const Tizen::Base::String& value) const + { + return value.GetHashCode(); + } + }; + + class _StringComparer + : public Tizen::Base::Collection::IComparerT + { + 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 __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 index 0000000..7dd1339 --- /dev/null +++ b/inc/FIo_ChannelServiceStub.h @@ -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 +#include +#include +#include +#include +#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 index 0000000..b882bf9 --- /dev/null +++ b/inc/FIo_ChannelWebAppStub.h @@ -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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 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_ + diff --git a/inc/FIo_MessagePortService.h b/inc/FIo_MessagePortService.h index a9a3a58..0dfab26 100644 --- a/inc/FIo_MessagePortService.h +++ b/inc/FIo_MessagePortService.h @@ -25,6 +25,8 @@ #ifndef _FIO_INTERNAL_MESSAGE_PORT_SERVICE_H_ #define _FIO_INTERNAL_MESSAGE_PORT_SERVICE_H_ +#include + #include #include #include @@ -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 @@ -105,6 +88,4 @@ private: Tizen::Base::Collection::HashMapT * __pTrustedPorts; }; // _MessagePortService -} } // Tizen::Io - #endif // _FIO_INTERNAL_MESSAGE_PORT_SERVICE_H_ diff --git a/inc/FIo_MessagePortStub.h b/inc/FIo_MessagePortStub.h index e56693d..5510bc7 100644 --- a/inc/FIo_MessagePortStub.h +++ b/inc/FIo_MessagePortStub.h @@ -26,27 +26,26 @@ #ifndef _FIO_INTERNAL_MESSAGE_PORT_STUB_H_ #define _FIO_INTERNAL_MESSAGE_PORT_STUB_H_ +#include + #include #include #include #include #include -#include +#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 index 0000000..eba3a32 --- /dev/null +++ b/inc/IIpcServerEventListener.h @@ -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 +//#include + +#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 index 0000000..e40b335 --- /dev/null +++ b/inc/IpcServer.h @@ -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 +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#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 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 __clients; // pid of client is used for key +}; // IpcServer + +#endif // _IPC_SERVER_H_ diff --git a/manifest.xml b/manifest.xml index de93d5a..bfd2e78 100644 --- a/manifest.xml +++ b/manifest.xml @@ -17,7 +17,7 @@ 2.1 9C645DDBA19C71BAD1204DA4DAA7A0B9 - + osp-channel-service diff --git a/osp-channel-service.manifest b/osp-channel-service.manifest index 051ee21..6896c16 100644 --- a/osp-channel-service.manifest +++ b/osp-channel-service.manifest @@ -1,12 +1,11 @@ - + - + - - \ No newline at end of file + diff --git a/packaging/osp-channel-service.spec b/packaging/osp-channel-service.spec index 8b6f0c2..03fda6b 100755 --- a/packaging/osp-channel-service.spec +++ b/packaging/osp-channel-service.spec @@ -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 index 0000000..9ac1990 --- /dev/null +++ b/src/FIo_ChannelCAppStub.cpp @@ -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 +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#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 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 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 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 index 0000000..dd79574 --- /dev/null +++ b/src/FIo_ChannelService.cpp @@ -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 +#include +#include + +#include + +#include +#include +#include +#include +#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* 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 index 0000000..f9abe4a --- /dev/null +++ b/src/FIo_ChannelServiceStub.cpp @@ -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 +#include +#include +#include + +#include +#include +#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(&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(&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 index 0000000..fe2fb6d --- /dev/null +++ b/src/FIo_ChannelWebAppStub.cpp @@ -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 +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#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(const_cast(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(m_header.factors.fin)); + SysLog(NID_IO, "masked: %d", static_cast(m_header.factors.masked)); + SysLog(NID_IO, "opcode: %d", static_cast(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(header.c_str()) + headerLength - _CHALLENGE_THIRD_INFO_SIZE; + char *pThirdInfoPos = const_cast(header) + headerLength - _CHALLENGE_THIRD_INFO_SIZE; + memcpy(thirdInfo, reinterpret_cast(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 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(pBuffer.get()), len); + SysTryReturn(NID_IO, ret >= 0, FALSE, E_SYSTEM, "[E_SYSTEM] Fail to parse the header!"); + + ret = message.ParsePayload(reinterpret_cast(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(temp)); + + // set MD5 hash + unsigned char hash[16]; + MD5((unsigned char*) temp, _CHALLENGE_RESPONSE_SIZE, hash); + + return std::string(reinterpret_cast(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(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 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(const_cast(response.c_str())), respSize); + SysTryLogReturn(NID_IO, ret >= 0, false, "ParseHeader error!"); + + ret = message.ParsePayload(reinterpret_cast(const_cast(response.c_str())), respSize); + SysTryLogReturn(NID_IO, ret >= 0, false, "ParsePayloadr error!"); + + message.ConsoleMessage(); + + return true; +} + +}} + diff --git a/src/FIo_MessagePortService.cpp b/src/FIo_MessagePortService.cpp index 5719aca..9dd9b39 100644 --- a/src/FIo_MessagePortService.cpp +++ b/src/FIo_MessagePortService.cpp @@ -22,20 +22,28 @@ #include +#include +#include + #include #include #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 - diff --git a/src/FIo_MessagePortStub.cpp b/src/FIo_MessagePortStub.cpp index fa05a40..df95596 100644 --- a/src/FIo_MessagePortStub.cpp +++ b/src/FIo_MessagePortStub.cpp @@ -21,9 +21,11 @@ * */ +#include + +#include + #include -#include -#include #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(&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(&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(&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 index 0000000..5c19df2 --- /dev/null +++ b/src/IpcServer.cpp @@ -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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +#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 (&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; +}