2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
19 * @file FIo_ChannelWebAppStub.cpp
20 * @brief This is the implementation file for the _ChannelWebAppStub class.
31 #include <unique_ptr.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
38 #include <netinet/in.h>
39 #include <arpa/inet.h>
42 #include <openssl/md5.h>
43 #include <openssl/sha.h>
44 #include <openssl/bio.h>
45 #include <openssl/evp.h>
46 #include <openssl/buffer.h>
48 #include <FBase_StringConverter.h>
49 #include <FBaseDataType.h>
50 #include <FBaseLong.h>
51 #include <FBaseColArrayList.h>
53 #include <FBaseRt_EventDispatcher.h>
54 #include <FBaseSysLog.h>
55 #include <FBaseUtilStringTokenizer.h>
56 #include <FIo_ChannelServiceStub.h>
57 #include <FApp_AppInfo.h>
59 #include "FIo_ChannelWebAppStub.h"
61 #define MAX_BUFFER_LENGTH 4096
63 #define htonll(x) ((((uint64_t)htonl(x)) << 32) + htonl(x >> 32))
64 #define ntohll(x) ((((uint64_t)ntohl(x)) << 32) + ntohl(x >> 32))
68 using namespace Tizen::Base;
69 using namespace Tizen::Base::Collection;
70 using namespace Tizen::Base::Runtime;
71 using namespace Tizen::Base::Utility;
72 using namespace Tizen::Io;
73 using namespace Tizen::App;
75 namespace Tizen { namespace Io
78 static const size_t _MAX_CONNECTIONS = 10;
79 static const size_t _MAX_BUFFER_SIZE = 1024;
80 static const int _PORT = 8080;
82 //static const char* webSocketServerAddr = "127.0.0.1";
83 static const char* webSocketHeaderId("Upgrade"); // web socket header identifier
84 static const char* webSocketHeaderKey("Sec-WebSocket-Key"); // hybi10
85 static const char* webSocketHeaderKey1("Sec-WebSocket-Key1"); // hybi00
86 static const char* webSocketHeaderKey2("Sec-WebSocket-Key2"); // hybi00
87 static const char* webSocketHeaderIdHybi10("websocket");
88 static const char* webSocketHeaderIdHybi00("WebSocket");
89 static const char* webSocketMagicString("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
91 static const int _CHALLENGE_NUMBER_SIZE = 4;
92 static const int _CHALLENGE_THIRD_INFO_SIZE = 8;
93 static const int _CHALLENGE_RESPONSE_SIZE = 16;
95 const unsigned char _SIMPLE_PAYLOAD_MAX_LEN = 125;
96 const unsigned char _EXTEND_PAYLOAD_TYPE_LEN16 = 0x7e; //126
97 const unsigned char _EXTEND_PAYLOAD_TYPE_LEN64 = 0x7f; //127
99 WebSocketType gHeaderType = WS_NONE;
103 OPCODE_CONTINUE = 0x0,
104 OPCODE_TEXT_MESSAGE = 0x1,
105 OPCODE_BIN_MESSAGE = 0x2,
106 OPCODE_CONNECTION_CLOSE = 0x8,
112 _ChannelWebAppStub::_WebSocketMessage::_WebSocketMessage(void)
115 , m_headerParsed(false)
120 _ChannelWebAppStub::_WebSocketMessage::~_WebSocketMessage(void)
126 _ChannelWebAppStub::_WebSocketMessage::CreateMessage(std::string& payload, std::string& message)
129 uint8_t *pCurrent = reinterpret_cast<uint8_t*>(const_cast<char *>(message.c_str()));
130 uint8_t *pStart = pCurrent;
132 // fin: 1 , opcode: 1
135 // masked : 0 (no mask)
139 if (payload.size() > _SIMPLE_PAYLOAD_MAX_LEN)
141 if (payload.size() < 64 * 1024)
143 *pCurrent |= _EXTEND_PAYLOAD_TYPE_LEN16;
145 uint16_t length = payload.size();
147 // Change the byte order
148 length = htons(length);
150 memcpy(pCurrent, &length, 2);
151 pCurrent = pCurrent + 2;
155 *pCurrent |= _EXTEND_PAYLOAD_TYPE_LEN64;
157 uint64_t length = payload.size();
159 // Change the byte order
160 length = htonll(length);
162 memcpy(pCurrent, &length, 8);
163 pCurrent = pCurrent + 8;
168 *pCurrent |= payload.size();
172 memcpy(pCurrent, payload.c_str(), payload.size());
173 pCurrent = pCurrent + payload.size();
177 return pCurrent - pStart;
181 _ChannelWebAppStub::_WebSocketMessage::ParseHeader(uint8_t* message, int messageLen)
183 SysTryLogReturn(NID_IO, message != null, -1, "message is null");
185 SysLog(NID_IO, "message = %s, size = %d", message, messageLen);
187 uint8_t* pCurrent = message;
190 m_header.factors.fin = 0x1 & *pCurrent >> 7;
191 // check 'opcode' bit
192 m_header.factors.opcode = 0xf & *pCurrent;
195 // check 'masked' bit
196 m_header.factors.masked = 0x1 & *pCurrent >> 7;
197 // check 'payload' type bit
198 m_header.factors.payloadLen = 0x7f & *pCurrent;
201 // set payload length
203 if (m_header.factors.payloadLen == _EXTEND_PAYLOAD_TYPE_LEN16)
205 SysLog(NID_IO, "extended payload len 16");
208 memcpy(&length, pCurrent, 2);
210 // Change the byte order
211 m_payloadLen = ntohs(length);
213 pCurrent = pCurrent + 2; // jump two byte
215 else if (m_header.factors.payloadLen == _EXTEND_PAYLOAD_TYPE_LEN64)
217 SysLog(NID_IO, "extended payload len 64");
220 memcpy(&length, pCurrent, 8);
222 // Change the byte order
223 m_payloadLen = ntohll(length);
225 pCurrent = pCurrent + 8; // jump eight byte
229 SysLog(NID_IO, "default payload len");
230 m_payloadLen = m_header.factors.payloadLen;
233 SysLog(NID_IO, "m_payloadLen = %lld", m_payloadLen);
235 SysTryLogReturn(NID_IO, m_payloadLen <= (uint64_t)messageLen, -1, "header parsing error!");
238 if (m_header.factors.masked == 1)
240 memcpy(m_maskingKey, pCurrent, 4);
241 pCurrent = pCurrent + 4; // jump four byte
244 m_payloadOffset = pCurrent - message;
245 m_headerParsed = true;
247 SysLog(NID_IO, "m_payloadOffset = %d", m_payloadOffset);
253 _ChannelWebAppStub::_WebSocketMessage::ParsePayload(uint8_t* message, int messageLen)
255 SysTryLogReturn(NID_IO, message != null, -1, "message is null");
257 SysLog(NID_IO, "message = %s", message);
259 SysTryLogReturn(NID_IO, m_payloadLen <= (uint64_t)messageLen, -1, "payloadLen is invalid!");
260 SysTryLogReturn(NID_IO, m_headerParsed == true, -1, "header not existed!");
262 // set payload length
263 m_payload = new (std::nothrow) uint8_t[m_payloadLen + 1];
264 SysTryLogReturn(NID_IO, m_payload != null, -1, "[E_OUT_OF_MEMORY] The memory is insufficient.");
266 memcpy(m_payload, message + m_payloadOffset, m_payloadLen);
268 // apply masking key to payload
269 if (m_header.factors.masked == 1)
271 uint8_t *payload = m_payload;
272 for (uint64_t i = 0; i < m_payloadLen; i++)
274 payload[i] ^= m_maskingKey[i % 4];
276 payload[m_payloadLen] = '\0';
283 _ChannelWebAppStub::_WebSocketMessage::ConsoleMessage(void) const
285 SysLog(NID_IO, "fin: %d", static_cast<bool>(m_header.factors.fin));
286 SysLog(NID_IO, "masked: %d", static_cast<bool>(m_header.factors.masked));
287 SysLog(NID_IO, "opcode: %d", static_cast<uint8_t>(m_header.factors.opcode));
288 SysLog(NID_IO, "payload: %s", m_payload);
289 SysLog(NID_IO, "payload len: %d", m_payloadLen);
292 _ChannelWebAppStub::_ChannelInfo::_ChannelInfo(void)
296 , destroySource(true)
300 _ChannelWebAppStub::_ChannelInfo::~_ChannelInfo(void)
302 if (pGIOChannel != null)
304 g_io_channel_unref(pGIOChannel);
307 if (pGSource != null)
311 g_source_destroy(pGSource);
314 g_source_unref(pGSource);
318 _ChannelWebAppStub::_ClientInfo::_ClientInfo(void)
323 _ChannelWebAppStub::_ClientInfo::~_ClientInfo(void)
328 _ChannelWebAppStub::_ChannelWebAppStub(void)
329 : __pChannelService(null)
330 , __pGMainContext(null)
331 , __pServerGSource(null)
332 , __pClientGSource(null)
337 _ChannelWebAppStub::~_ChannelWebAppStub(void)
339 if (__pServerGSource != null)
341 g_source_destroy(__pServerGSource);
342 g_source_unref(__pServerGSource);
343 __pServerGSource = null;
348 _ChannelWebAppStub::Construct(void)
350 GSource* pGSource = null;
351 GIOChannel* pGIOChannel = null;
352 struct sockaddr_in socketInfo;
353 int serverSocket = -1;
355 result r = E_SUCCESS;
357 __pClients = new (std::nothrow) HashMap();
358 SysTryReturnResult(NID_IO, __pClients != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
359 __pClients->Construct(50);
361 __pGMainContext = g_main_context_get_thread_default(); //get own gmain context except default thread
362 if (__pGMainContext == null)
364 __pGMainContext = g_main_context_default(); //get gmain context from me (default)
365 SysTryReturnResult(NID_IO, __pGMainContext != null, E_SYSTEM,
366 "Failed to get glib context.");
369 // create native socket
370 // set non-blocking socket mode
371 serverSocket = socket(AF_INET,
372 SOCK_STREAM | SOCK_NONBLOCK,
375 SysTryReturnResult(NID_IO, serverSocket != -1, E_SYSTEM,
376 "Failed to create a socket.");
379 ret = setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse));
380 SysTryCatch(NID_IO, ret != -1, r = E_SYSTEM, E_SYSTEM,
381 "[E_SYSTEM] Failed to set options on socket(%d, %s): %d", serverSocket, strerror(errno), errno);
383 // create native socket of server
384 memset(&socketInfo, 0, sizeof(socketInfo));
385 socketInfo.sin_family = AF_INET;
386 //socketInfo.sin_addr.s_addr = inet_addr(webSocketServerAddr);
387 //socketInfo.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
388 socketInfo.sin_addr.s_addr = htonl(INADDR_ANY);
389 socketInfo.sin_port = htons(_PORT);
391 // bind local address
392 ret = bind(serverSocket,
393 (const struct sockaddr*) &socketInfo,
394 sizeof(struct sockaddr_in));
395 SysTryCatch(NID_IO, ret != -1, r = E_SYSTEM, E_SYSTEM,
396 "[E_SYSTEM] Failed to bind a socket(%d, %s): %d", serverSocket, strerror(errno), errno);
398 listen(serverSocket, _MAX_CONNECTIONS);
400 pGIOChannel = g_io_channel_unix_new(serverSocket);
401 SysTryCatch(NID_IO, pGIOChannel != null, r = E_SYSTEM, E_SYSTEM,
402 "[E_SYSTEM] Failed to create GIOChannel for socket.");
404 // socket will be closed when pGIOChannel is deleted.
405 g_io_channel_set_close_on_unref(pGIOChannel, TRUE);
408 pGSource = g_io_create_watch(pGIOChannel, (GIOCondition)(G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP));
409 SysTryCatch(NID_IO, pGSource != null, r = E_SYSTEM, E_SYSTEM,
410 "[E_SYSTEM] Failed to create GSource for socket.");
412 // channel will be delete when pGSource is deleted.
413 g_io_channel_unref(pGIOChannel);
416 g_source_set_callback(pGSource, (GSourceFunc) OnConnectionRequest, this, NULL);
417 g_source_attach(pGSource, __pGMainContext);
419 __pServerGSource = pGSource;
424 if (pGIOChannel != null)
426 g_io_channel_unref(pGIOChannel);
429 if (serverSocket != -1)
436 g_main_context_unref(__pGMainContext);
437 __pGMainContext = null;
444 _ChannelWebAppStub::SetChannelService(_ChannelService& service)
446 __pChannelService = &service;
450 _ChannelWebAppStub::OnConnectionRequest(GIOChannel* source, GIOCondition condition, gpointer data)
454 struct sockaddr_in socketInfo;
455 socklen_t socketInfoLength = sizeof(socketInfo);
456 GSource* pGSource = null;
457 GIOChannel* pGIOChannel = null;
458 GError* pGError = null;
459 _ClientInfo* pClientInfo = null;
460 _ChannelInfo* pChannelInfo = null;
461 WebSocketType headerType;
462 SoupMessageHeaders* pSoupHeader = null;
470 _ChannelWebAppStub* pChannelStub = static_cast< _ChannelWebAppStub* >(data);
471 SysTryReturn(NID_IO, pChannelStub != null, FALSE, E_SYSTEM,
472 "[E_SYSTEM] pChannelStub is null.");
474 serverFd = g_io_channel_unix_get_fd(source);
476 clientFd = accept(serverFd,
477 (struct sockaddr*) &socketInfo,
479 SysTryReturn(NID_IO, clientFd != -1, FALSE, E_SYSTEM, "[E_SYSTEM] Failed to accept.");
482 std::string headerData;
483 char header[_MAX_BUFFER_SIZE + 1] = {0,};
484 int headerLength = recv(clientFd, (char*)(header), _MAX_BUFFER_SIZE, 0);
485 if (headerLength < 0)
487 SysLog(NID_IO, "errno = %d %s", errno, strerror(errno));
488 SysLog(NID_IO, "headerLength = %d", headerLength);
489 SysLog(NID_IO, "Recv header = %s", header);
491 SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Failed to recv, header length is less than 0.");
495 SysLog(NID_IO, "recv - header length = %d", headerLength);
496 SysLog(NID_IO, "recv - header data = %s", header);
498 pGIOChannel = g_io_channel_unix_new(clientFd);
499 SysTryCatch(NID_IO, pGIOChannel != null, , E_SYSTEM, "[E_SYSTEM] Failed to create GIOChannel.");
501 g_io_channel_set_encoding(pGIOChannel, NULL, &pGError);
502 g_io_channel_set_flags(pGIOChannel, G_IO_FLAG_NONBLOCK, &pGError);
504 g_io_channel_set_close_on_unref(pGIOChannel, TRUE);
507 // Handshake with WebApp
508 // check if header of app socket is not for websocket
510 headerType = VerifyHttpHeaderType(headerData, headerLength);
512 SysLog(NID_IO, "VerifyHttpHeader, type = %d", headerType);
514 if (headerType == WS_NONE)
516 SysLog(NID_IO, "Unpermitted header type");
520 // Set the header type
521 gHeaderType = headerType;
524 // create soup header
525 pSoupHeader = soup_message_headers_new(SOUP_MESSAGE_HEADERS_REQUEST);
526 //soup_headers_parse(header.c_str(), headerLength, pSoupHeader);
527 soup_headers_parse(header, headerLength, pSoupHeader);
529 if (headerType == WS_HYBI00)
531 SysLog(NID_IO, "WS_HYBI00");
533 // get third information from http header
534 unsigned int firstInfo = ExtractChallengeNumber(
535 soup_message_headers_get_one(pSoupHeader, webSocketHeaderKey1));
536 unsigned int secondInfo = ExtractChallengeNumber(
537 soup_message_headers_get_one(pSoupHeader, webSocketHeaderKey2));
538 unsigned char thirdInfo[8];
539 //char *pThirdInfoPos = const_cast<char*>(header.c_str()) + headerLength - _CHALLENGE_THIRD_INFO_SIZE;
540 char *pThirdInfoPos = const_cast<char*>(header) + headerLength - _CHALLENGE_THIRD_INFO_SIZE;
541 memcpy(thirdInfo, reinterpret_cast<unsigned char*>(pThirdInfoPos), _CHALLENGE_THIRD_INFO_SIZE);
543 // make challenge response data for hybi00
544 const std::string response = MakeHybi00Response(firstInfo, secondInfo, thirdInfo);
545 // create response header to be sent to app
546 std::string responseHeader = CreateResponseHeader(clientFd, pSoupHeader, response);
547 // send response header
548 len = send(clientFd, responseHeader.c_str(), responseHeader.size(), 0);
551 else if (headerType == WS_HYBI10)
553 SysLog(NID_IO, "WS_HYBI10");
555 const char* pSecureKeyValue = soup_message_headers_get_one(
556 pSoupHeader, webSocketHeaderKey);
558 std::string secureKey(pSecureKeyValue);
559 secureKey.append(webSocketMagicString);
561 // make Sec-WebSocket-Accept data for hybi10
562 const std::string response = MakeHybi10Response(secureKey);
564 // create response header to be sent to app
565 std::string responseHeader = CreateResponseHeader(clientFd, pSoupHeader, response);
567 // send response header
568 SysLog(NID_IO, "Send responseHeader = %s", responseHeader.c_str());
569 len = send(clientFd, responseHeader.c_str(), responseHeader.size(), 0);
572 SysLog(NID_IO, "errno = %d %s", errno, strerror(errno));
573 SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Failed to send responseHeader, length is less than 1.");
579 SysLog(NID_IO, "ELSE");
584 SysLog(NID_IO, "Failed to send responseHeader");
585 SysLog(NID_IO, "errno = %d %s", errno, strerror(errno));
590 // Parse and set appId for WebApp
593 String headerString(header);
595 // header = "GET /ipc?src=abcde1234.WebApp&dest=4z6olle215.Dictionary HTTP/1.1^M"
596 StringTokenizer st(headerString, L" /?=&");
597 st.GetNextToken(tempStr); // GET
598 st.GetNextToken(tempStr); // ipc
599 st.GetNextToken(tempStr); // src
600 st.GetNextToken(srcAppId);
601 st.GetNextToken(tempStr); // dest
602 st.GetNextToken(destAppId);
605 // Check the destAppId
606 out = pChannelStub->__pChannelService->IsChannelRegistered(destAppId);
607 SysTryCatch(NID_IO, out, , E_SYSTEM, "[E_SYSTEM] Destination channel is not found.");
611 pChannelStub->__pClients->ContainsKey(key, out);
612 if (!out) // first connection request from this client
614 SysLog(NID_IO, "First Connection of WebApp - AppId = %ls", srcAppId.GetPointer());
616 pClientInfo = new (std::nothrow) _ClientInfo();
618 pClientInfo->srcAppId = srcAppId;
619 //pClientInfo->srcAppExecName = srcAppExecName;
620 pClientInfo->pChannelStub = pChannelStub;
621 //pClientInfo->clientId = clientFd;
622 pClientInfo->key = key;
624 pChannelStub->__pClients->Add(*(new String(key)), *pClientInfo);
626 // Stores client info to _ChannelService
627 SysLog(NID_IO, "Register Channel for WebApp");
629 pChannelStub->__pChannelService->RegisterChannel(srcAppId, clientFd, WEBAPP_CHANNEL);
632 SysLog(NID_IO, "srcAppId = %ls, destAppId = %ls", srcAppId.GetPointer(), destAppId.GetPointer());
635 pChannelInfo = new (std::nothrow) _ChannelInfo;
636 SysTryCatch(NID_IO, pChannelInfo != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
638 pGSource = g_io_create_watch(pGIOChannel, (GIOCondition) (G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP));
640 g_source_set_callback(pGSource, (GSourceFunc) OnReadMessage, pChannelInfo, NULL);
641 g_source_attach(pGSource, ((_ChannelWebAppStub*)data)->__pGMainContext);
643 pChannelStub->__pClientGSource = pGSource;
647 pChannelInfo->pClientInfo = pClientInfo;
648 pChannelInfo->pGIOChannel = pGIOChannel;
649 pChannelInfo->pGSource = pGSource;
650 pChannelInfo->destAppId = destAppId;
652 pClientInfo->channels.push_back(pChannelInfo);
658 if (pGIOChannel != null)
660 g_io_channel_unref(pGIOChannel);
672 _ChannelWebAppStub::OnReadMessage(GIOChannel* source, GIOCondition condition, gpointer data)
674 SysLog(NID_IO, "Callback");
676 gboolean ret = FALSE;
678 _ChannelInfo* pChannelInfo = (_ChannelInfo*) data;
679 _ClientInfo* pClientInfo = pChannelInfo->pClientInfo;
680 _ChannelWebAppStub* pChannelStub = (_ChannelWebAppStub*) pClientInfo->pChannelStub;
681 ret = pChannelStub->HandleReceivedMessage(source, condition, data);
687 _ChannelWebAppStub::HandleReceivedMessage(GIOChannel* source, GIOCondition condition, gpointer data)
689 result r = E_SUCCESS;
690 GError* pGError = null;
691 int clientFd = g_io_channel_unix_get_fd(source);
693 SysLog(NID_IO, "HandleMessage - client = %d", clientFd);
695 _ChannelInfo* pChannelInfo = (_ChannelInfo*) data;
696 _ClientInfo* pClientInfo = pChannelInfo->pClientInfo;
697 _ChannelWebAppStub* pChannelStub = (_ChannelWebAppStub*) pClientInfo->pChannelStub;
699 if (condition & G_IO_HUP)
701 SysLog(NID_IO, "G_IO_HUP - connection closed");
703 g_io_channel_shutdown(source, FALSE, &pGError);
705 for (unsigned int i = 0; i < pClientInfo->channels.size(); i++)
707 if (pChannelInfo == pClientInfo->channels[i])
709 pClientInfo->channels.erase(pClientInfo->channels.begin() + i);
711 // Do not destroy a source in a dispatch callback
712 // because main loop will do it if the callback return FALSE.
713 pChannelInfo->destroySource = false;
720 if (pClientInfo->channels.size() == 0)
722 SysLog(NID_IO, "All connections of client(%ls) are closed. delete client info", pClientInfo->srcAppId.GetPointer());
724 String key = pClientInfo->srcAppId;
725 __pClients->Remove(key, false);
729 pChannelStub->__pChannelService->UnregisterChannel(clientFd);
734 else if (condition & G_IO_IN)
736 SysLog(NID_IO, "G_IO_IN");
738 unique_ptr<char[]> pBuffer(new char[MAX_BUFFER_LENGTH]);
739 int len = recv(clientFd, (char *)pBuffer.get(), MAX_BUFFER_LENGTH, 0);
742 SysLog(NID_IO, "recv error: errno = %d %s", errno, strerror(errno));
743 SysLog(NID_IO, "headerLength = %d", len);
744 SysLog(NID_IO, "Recv header = %s", pBuffer.get());
746 SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Failed to recv, length is less than 0.");
752 SysLog(NID_IO, "The peer has performed an orderly shutdown, recv = %d", len);
754 g_io_channel_shutdown(source, FALSE, &pGError);
756 for (unsigned int i = 0; i < pClientInfo->channels.size(); i++)
758 if (pChannelInfo == pClientInfo->channels[i])
760 pClientInfo->channels.erase(pClientInfo->channels.begin() + i);
762 // Do not destroy a source in a dispatch callback
763 // because main loop will do it if the callback return FALSE.
764 pChannelInfo->destroySource = false;
771 if (pClientInfo->channels.size() == 0)
773 SysLog(NID_IO, "All connections of client(%ls) are closed. delete client info", pClientInfo->srcAppId.GetPointer());
775 String key = pClientInfo->srcAppId;
776 __pClients->Remove(key, false);
780 pChannelStub->__pChannelService->UnregisterChannel(clientFd);
786 if (gHeaderType == WS_HYBI00)
788 // Not supported because of old websocket protocol
789 SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Not supported protocol.");
793 else if (gHeaderType == WS_HYBI10)
795 SysLog(NID_IO,"WS_HYBI10 is supported, received data: %s (%d)", pBuffer.get(), len);
797 // Current webkit of tizen support
798 _WebSocketMessage message;
800 ret = message.ParseHeader(reinterpret_cast<uint8_t*>(pBuffer.get()), len);
801 SysTryReturn(NID_IO, ret >= 0, FALSE, E_SYSTEM, "[E_SYSTEM] Fail to parse the header!");
803 ret = message.ParsePayload(reinterpret_cast<uint8_t*>(pBuffer.get()), len);
804 SysTryReturn(NID_IO, ret >= 0, FALSE, E_SYSTEM, "[E_SYSTEM] Fail to parse the payload!");
806 message.ConsoleMessage();
808 // do something for opcode or custom protocol of payload
809 if (message.m_header.factors.opcode == OPCODE_CONNECTION_CLOSE)
811 SysLog(NID_IO,"OPCODE_CONNECTION_CLOSE with clientFd: %d", clientFd);
813 g_io_channel_shutdown(source, FALSE, &pGError);
815 for (unsigned int i = 0; i < pClientInfo->channels.size(); i++)
817 if (pChannelInfo == pClientInfo->channels[i])
819 pClientInfo->channels.erase(pClientInfo->channels.begin() + i);
821 // Do not destroy a source in a dispatch callback
822 // because main loop will do it if the callback return FALSE.
823 pChannelInfo->destroySource = false;
830 if (pClientInfo->channels.size() == 0)
832 SysLog(NID_IO, "All connections of client(%ls) are closed. delete client info", pClientInfo->srcAppId.GetPointer());
834 String key = pClientInfo->srcAppId;
835 __pClients->Remove(key, false);
839 pChannelStub->__pChannelService->UnregisterChannel(clientFd);
844 else if (message.m_header.factors.opcode == OPCODE_TEXT_MESSAGE)
852 list.Add(*(new String((char*)message.m_payload)));
854 SysLog(NID_IO, "srcAppId = %ls, destAppId = %ls", pClientInfo->srcAppId.GetPointer(), pChannelInfo->destAppId.GetPointer());
856 r = pChannelStub->__pChannelService->SendRequest(pClientInfo->srcAppId,
857 pChannelInfo->destAppId, list, reqId);
858 SysTryReturn(NID_IO, !IsFailed(r), FALSE, E_SYSTEM, "[E_SYSTEM] Failed to send request.");
860 list.RemoveAll(true);
864 // Not yet supported opcode
865 SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Not supported Opcode.");
872 SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Not supported protocol.");
880 SysLog(NID_IO, "G_IO else");
888 _ChannelWebAppStub::VerifyHttpHeaderType(std::string header, int headerLength)
891 SoupMessageHeaders* pSoupHeader =
892 soup_message_headers_new(SOUP_MESSAGE_HEADERS_REQUEST);
893 if (!soup_headers_parse(header.c_str(), headerLength, pSoupHeader))
898 WebSocketType headerType;
899 const char* pHeaderValue =
900 soup_message_headers_get_one(pSoupHeader, webSocketHeaderId);
904 SysLog(NID_IO, "Not for web socket header.");
908 if (strcmp(pHeaderValue, webSocketHeaderIdHybi00) == 0)
910 headerType = WS_HYBI00;
912 if (strcmp(pHeaderValue, webSocketHeaderIdHybi10) == 0)
914 headerType = WS_HYBI10;
918 headerType = WS_NONE;
925 _ChannelWebAppStub::CreateResponseHeader(int appSocket, SoupMessageHeaders *header,
926 const std::string& response)
928 std::string responseHeader;
930 //if (m_appSockets[appSocket] == WS_HYBI00) {
931 if (gHeaderType == WS_HYBI00)
933 responseHeader.append("HTTP/1.1 101 WebSocket Protocol Handshake\r\n");
934 responseHeader.append("Upgrade: WebSocket\r\n");
935 responseHeader.append("Connection: Upgrade\r\n");
936 responseHeader.append("Sec-WebSocket-Origin: ");
937 responseHeader.append(soup_message_headers_get_one(header, "Origin"));
938 responseHeader.append("\r\n");
939 responseHeader.append("Sec-WebSocket-Location: ws://");
940 responseHeader.append(soup_message_headers_get_one(header, "Host"));
941 responseHeader.append("\r\n");
942 responseHeader.append("\r\n");
943 responseHeader.append(response.c_str());
944 //} else if (m_appSockets[appSocket] == WS_HYBI10) {
946 else if (gHeaderType == WS_HYBI10)
948 responseHeader.append("HTTP/1.1 101 Switching Protocols\r\n");
949 responseHeader.append("Upgrade: websocket\r\n");
950 responseHeader.append("Connection: Upgrade\r\n");
951 responseHeader.append("Sec-WebSocket-Accept: ");
952 responseHeader.append(response.c_str());
953 responseHeader.append("\r\n");
954 responseHeader.append("\r\n");
955 // TODO Sec-WebSocket-Protocol support
959 responseHeader = std::string();
962 return responseHeader;
966 _ChannelWebAppStub::MakeHybi00Response(uint32_t first, uint32_t second, uint8_t* third)
968 SysAssertf(third != null, "The input parameter third should not be null.");
970 if (sizeof(third) != _CHALLENGE_NUMBER_SIZE)
972 SysLog(NID_IO, "Invalid third argument.");
977 uint8_t temp[_CHALLENGE_RESPONSE_SIZE];
978 result = AppendChallengeNumber(first, &temp[0]);
981 SysLog(NID_IO, "Failed to set challenge number.");
985 result = AppendChallengeNumber(second, &temp[4]);
988 SysLog(NID_IO, "Failed to set challenge number.");
992 memcpy(temp + 8, third, _CHALLENGE_THIRD_INFO_SIZE);
993 SysLog(NID_IO,"Challenge Response before md5 : %s", reinterpret_cast<char *>(temp));
996 unsigned char hash[16];
997 MD5((unsigned char*) temp, _CHALLENGE_RESPONSE_SIZE, hash);
999 return std::string(reinterpret_cast<const char*>(hash));
1003 _ChannelWebAppStub::MakeHybi10Response(std::string& secureAccept)
1005 if (secureAccept.empty())
1007 SysLog(NID_IO, "Invalid argruments");
1011 unsigned char hash[20];
1012 SHA1(reinterpret_cast<const unsigned char*>(secureAccept.c_str()),
1013 secureAccept.size(),
1016 return std::string(EncodeBase64(hash, 20));
1020 _ChannelWebAppStub::AppendChallengeNumber(uint32_t number, unsigned char *response)
1024 SysLog(NID_IO, "Invalid response string");
1028 // by spec, challenge number should be added as big endian
1029 unsigned char* pIdx = response + 3;
1030 for (int i = 0; i < 4; i++)
1032 *pIdx = 0xff & number;
1041 _ChannelWebAppStub::ExtractChallengeNumber(const char* keyString)
1045 SysLog(NID_IO, "Invalid secure key");
1051 std::string secureKey(keyString);
1052 std::string::iterator it;
1054 for (it = secureKey.begin(); it < secureKey.end(); it++)
1060 else if ((*it >= '0') && (*it <= '9'))
1062 digits.insert(digits.end(), 1, *it);
1066 std::istringstream stream(digits);
1067 unsigned int numFromDigits = 0;
1068 stream >> numFromDigits;
1070 return space ? (numFromDigits / space) : numFromDigits;
1074 _ChannelWebAppStub::EncodeBase64(unsigned char *string, int len)
1078 BUF_MEM* pBptr = null;
1080 pB64 = BIO_new(BIO_f_base64());
1081 pBmem = BIO_new(BIO_s_mem());
1082 pB64 = BIO_push(pB64, pBmem);
1083 BIO_write(pB64, string, len);
1085 BIO_get_mem_ptr(pB64, &pBptr);
1087 char* pBuff = (char *)malloc(pBptr->length);
1088 SysTryLogReturn(NID_IO, pBuff != NULL, NULL, "The memory is insufficient.");
1089 memcpy(pBuff, pBptr->data, pBptr->length-1);
1090 pBuff[pBptr->length-1] = 0;
1097 _ChannelWebAppStub::SendResponse(int clientId, const ArrayList& args)
1099 unique_ptr<char[]> pStr(_StringConverter::CopyToCharArrayN(*((String*)args.GetAt(0))));
1101 SysLog(NID_IO, "clientId = %d, data = %s", clientId, pStr.get());
1104 string payload(pStr.get());
1106 int respSize = _WebSocketMessage::CreateMessage(payload, response);
1107 int ret = send(clientId, response.c_str(), respSize, 0);
1108 SysTryLogReturn(NID_IO, ret >= 1, false, "Failed to send data. Length is less than 1. errno = %d %s", errno, strerror(errno));
1110 SysLog(NID_IO, "response = %s, size = %d", response.c_str(), ret);
1112 _WebSocketMessage message;
1113 ret = message.ParseHeader(reinterpret_cast<uint8_t*>(const_cast<char*>(response.c_str())), respSize);
1114 SysTryLogReturn(NID_IO, ret >= 0, false, "ParseHeader error!");
1116 ret = message.ParsePayload(reinterpret_cast<uint8_t*>(const_cast<char*>(response.c_str())), respSize);
1117 SysTryLogReturn(NID_IO, ret >= 0, false, "ParsePayloadr error!");
1119 message.ConsoleMessage();