+++ /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;
-}
-
-}}
-