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