Update the spec file
[platform/framework/native/channel-service.git] / src / FIo_ChannelWebAppStub.cpp
1 //
2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 //
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
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
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.
16 //
17
18 /**
19  * @file        FIo_ChannelWebAppStub.cpp
20  * @brief       This is the implementation file for the  _ChannelWebAppStub class.
21  *
22  */
23
24 #include <cstdio>
25 #include <cstdlib>
26 #include <cstring>
27 #include <cerrno>
28 #include <iostream>
29 #include <sstream>
30
31 #include <unique_ptr.h>
32
33 #include <unistd.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <sys/stat.h>
37 #include <sys/un.h>
38 #include <netinet/in.h>
39 #include <arpa/inet.h>
40 #include <errno.h>
41
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>
47
48 #include <FBase_StringConverter.h>
49 #include <FBaseDataType.h>
50 #include <FBaseLong.h>
51 #include <FBaseColArrayList.h>
52
53 #include <FBaseRt_EventDispatcher.h>
54 #include <FBaseSysLog.h>
55 #include <FBaseUtilStringTokenizer.h>
56 #include <FIo_ChannelServiceStub.h>
57 #include <FApp_AppInfo.h>
58
59 #include "FIo_ChannelWebAppStub.h"
60
61 #define MAX_BUFFER_LENGTH 4096
62
63 #define htonll(x)   ((((uint64_t)htonl(x)) << 32) + htonl(x >> 32))
64 #define ntohll(x)   ((((uint64_t)ntohl(x)) << 32) + ntohl(x >> 32))
65
66 using namespace std;
67
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;
74
75 namespace Tizen { namespace Io
76 {
77
78 static const size_t _MAX_CONNECTIONS = 10;
79 static const size_t _MAX_BUFFER_SIZE = 1024;
80 static const int _PORT = 8080;
81
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");
90
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;
94
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
98
99 WebSocketType gHeaderType = WS_NONE;
100
101 enum WebSocketOpcode
102 {
103         OPCODE_CONTINUE = 0x0,
104         OPCODE_TEXT_MESSAGE = 0x1,
105         OPCODE_BIN_MESSAGE = 0x2,
106         OPCODE_CONNECTION_CLOSE = 0x8,
107         OPCODE_PING = 0x9,
108         OPCODE_PONG = 0xA
109 };
110
111
112 _ChannelWebAppStub::_WebSocketMessage::_WebSocketMessage(void)
113         : m_payloadOffset(0)
114         , m_payloadLen(0)
115         , m_headerParsed(false)
116         , m_payload(null)
117 {
118 }
119
120 _ChannelWebAppStub::_WebSocketMessage::~_WebSocketMessage(void)
121 {
122         delete[] m_payload;
123 }
124
125 size_t
126 _ChannelWebAppStub::_WebSocketMessage::CreateMessage(std::string& payload, std::string& message)
127 {
128         message.clear();
129         uint8_t *pCurrent = reinterpret_cast<uint8_t*>(const_cast<char *>(message.c_str()));
130         uint8_t *pStart = pCurrent;
131
132         // fin: 1 , opcode: 1
133         *pCurrent |= 0x81;
134         pCurrent++;
135         // masked : 0 (no mask)
136         *pCurrent &= 0x00;
137
138         // set payload len
139         if (payload.size() > _SIMPLE_PAYLOAD_MAX_LEN)
140         {
141                 if (payload.size() < 64 * 1024)
142                 {
143                         *pCurrent |= _EXTEND_PAYLOAD_TYPE_LEN16;
144                         pCurrent++;
145                         uint16_t length = payload.size();
146
147                         // Change the byte order
148                         length = htons(length);
149
150                         memcpy(pCurrent, &length, 2);
151                         pCurrent = pCurrent + 2;
152                 }
153                 else
154                 {
155                         *pCurrent |= _EXTEND_PAYLOAD_TYPE_LEN64;
156                         pCurrent++;
157                         uint64_t length = payload.size();
158
159                         // Change the byte order
160                         length = htonll(length);
161
162                         memcpy(pCurrent, &length, 8);
163                         pCurrent = pCurrent + 8;
164                 }
165         }
166         else
167         {
168                 *pCurrent |= payload.size();
169                 pCurrent++;
170         }
171
172         memcpy(pCurrent, payload.c_str(), payload.size());
173         pCurrent = pCurrent + payload.size();
174         //*pCurrent = '\0';
175         //pCurrent++;
176
177         return pCurrent - pStart;
178 }
179
180 int
181 _ChannelWebAppStub::_WebSocketMessage::ParseHeader(uint8_t* message, int messageLen)
182 {
183         SysTryLogReturn(NID_IO, message != null, -1, "message is null");
184
185         SysLog(NID_IO, "message = %s, size = %d", message, messageLen);
186
187         uint8_t* pCurrent = message;
188
189         // check 'fin' bit
190         m_header.factors.fin = 0x1 & *pCurrent >> 7;
191         // check 'opcode' bit
192         m_header.factors.opcode = 0xf & *pCurrent;
193         pCurrent++;
194
195         // check 'masked' bit
196         m_header.factors.masked = 0x1 & *pCurrent >> 7;
197         // check 'payload' type bit
198         m_header.factors.payloadLen = 0x7f & *pCurrent;
199         pCurrent++;
200
201         // set payload length
202         m_payloadLen = 0;
203         if (m_header.factors.payloadLen == _EXTEND_PAYLOAD_TYPE_LEN16)
204         {
205                 SysLog(NID_IO, "extended payload len 16");
206
207                 uint16_t length = 0;
208                 memcpy(&length, pCurrent, 2);
209
210                 // Change the byte order
211                 m_payloadLen = ntohs(length);
212
213                 pCurrent = pCurrent + 2; // jump two byte
214         }
215         else if (m_header.factors.payloadLen == _EXTEND_PAYLOAD_TYPE_LEN64)
216         {
217                 SysLog(NID_IO, "extended payload len 64");
218
219                 uint64_t length = 0;
220                 memcpy(&length, pCurrent, 8);
221
222                 // Change the byte order
223                 m_payloadLen = ntohll(length);
224
225                 pCurrent = pCurrent + 8; // jump eight byte
226         }
227         else
228         {
229                 SysLog(NID_IO, "default payload len");
230                 m_payloadLen = m_header.factors.payloadLen;
231         }
232
233         SysLog(NID_IO, "m_payloadLen = %lld", m_payloadLen);
234
235         SysTryLogReturn(NID_IO, m_payloadLen <= (uint64_t)messageLen, -1, "header parsing error!");
236
237         // set masking-key
238         if (m_header.factors.masked == 1)
239         {
240                 memcpy(m_maskingKey, pCurrent, 4);
241                 pCurrent = pCurrent + 4; // jump four byte
242         }
243
244         m_payloadOffset = pCurrent - message;
245         m_headerParsed = true;
246
247         SysLog(NID_IO, "m_payloadOffset = %d", m_payloadOffset);
248
249         return 0;
250 }
251
252 int
253 _ChannelWebAppStub::_WebSocketMessage::ParsePayload(uint8_t* message, int messageLen)
254 {
255         SysTryLogReturn(NID_IO, message != null, -1, "message is null");
256
257         SysLog(NID_IO, "message = %s", message);
258
259         SysTryLogReturn(NID_IO, m_payloadLen <= (uint64_t)messageLen, -1, "payloadLen is invalid!");
260         SysTryLogReturn(NID_IO, m_headerParsed == true, -1, "header not existed!");
261
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.");
265
266         memcpy(m_payload, message + m_payloadOffset, m_payloadLen);
267
268         // apply masking key to payload
269         if (m_header.factors.masked == 1)
270         {
271                 uint8_t *payload = m_payload;
272                 for (uint64_t i = 0; i < m_payloadLen; i++)
273                 {
274                         payload[i] ^= m_maskingKey[i % 4];
275                 }
276                 payload[m_payloadLen] = '\0';
277         }
278
279         return 0;
280 }
281
282 void
283 _ChannelWebAppStub::_WebSocketMessage::ConsoleMessage(void) const
284 {
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);
290 }
291
292 _ChannelWebAppStub::_ChannelInfo::_ChannelInfo(void)
293         : pClientInfo(null)
294         , pGIOChannel(null)
295         , pGSource(null)
296         , destroySource(true)
297 {
298 }
299
300 _ChannelWebAppStub::_ChannelInfo::~_ChannelInfo(void)
301 {
302         if (pGIOChannel != null)
303         {
304                 g_io_channel_unref(pGIOChannel);
305         }
306
307         if (pGSource != null)
308         {
309                 if (destroySource)
310                 {
311                         g_source_destroy(pGSource);
312                 }
313
314                 g_source_unref(pGSource);
315         }
316 }
317
318 _ChannelWebAppStub::_ClientInfo::_ClientInfo(void)
319         : pChannelStub(null)
320 {
321 }
322
323 _ChannelWebAppStub::_ClientInfo::~_ClientInfo(void)
324 {
325         channels.clear();
326 }
327
328 _ChannelWebAppStub::_ChannelWebAppStub(void)
329         : __pChannelService(null)
330         , __pGMainContext(null)
331         , __pServerGSource(null)
332         , __pClientGSource(null)
333         , __pClients(null)
334 {
335 }
336
337 _ChannelWebAppStub::~_ChannelWebAppStub(void)
338 {
339         if (__pServerGSource != null)
340         {
341                 g_source_destroy(__pServerGSource);
342                 g_source_unref(__pServerGSource);
343                 __pServerGSource = null;
344         }
345 }
346
347 result
348 _ChannelWebAppStub::Construct(void)
349 {
350         GSource* pGSource = null;
351         GIOChannel* pGIOChannel = null;
352         struct sockaddr_in socketInfo;
353         int serverSocket = -1;
354         int ret = 0;
355         result r = E_SUCCESS;
356
357         __pClients = new (std::nothrow) HashMap();
358         SysTryReturnResult(NID_IO, __pClients != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
359         __pClients->Construct(50);
360
361         __pGMainContext = g_main_context_get_thread_default(); //get own gmain context except default thread
362         if (__pGMainContext == null)
363         {
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.");
367         }
368
369         // create native socket
370         // set non-blocking socket mode
371         serverSocket = socket(AF_INET,
372                      SOCK_STREAM | SOCK_NONBLOCK,
373                      IPPROTO_TCP);
374
375         SysTryReturnResult(NID_IO, serverSocket != -1, E_SYSTEM,
376                         "Failed to create a socket.");
377
378         int reuse = 1;
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);
382
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);
390
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);
397
398         listen(serverSocket, _MAX_CONNECTIONS);
399
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.");
403
404         // socket will be closed when pGIOChannel is deleted.
405         g_io_channel_set_close_on_unref(pGIOChannel, TRUE);
406         serverSocket = -1;
407
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.");
411
412         // channel will be delete when pGSource is deleted.
413         g_io_channel_unref(pGIOChannel);
414         pGIOChannel = null;
415
416         g_source_set_callback(pGSource, (GSourceFunc) OnConnectionRequest, this, NULL);
417         g_source_attach(pGSource, __pGMainContext);
418
419         __pServerGSource = pGSource;
420
421         return E_SUCCESS;
422
423 CATCH:
424         if (pGIOChannel != null)
425         {
426                 g_io_channel_unref(pGIOChannel);
427         }
428
429         if (serverSocket != -1)
430         {
431                 close(serverSocket);
432         }
433
434         if (__pGMainContext)
435         {
436                 g_main_context_unref(__pGMainContext);
437                 __pGMainContext = null;
438         }
439
440         return r;
441 }
442
443 void
444 _ChannelWebAppStub::SetChannelService(_ChannelService& service)
445 {
446         __pChannelService = &service;
447 }
448
449 gboolean
450 _ChannelWebAppStub::OnConnectionRequest(GIOChannel* source, GIOCondition condition, gpointer data)
451 {
452         int serverFd = -1;
453         int clientFd = -1;
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;
463         int len = -1;
464         bool out = false;
465
466         AppId srcAppId;
467         AppId destAppId;
468         String key;
469
470         _ChannelWebAppStub* pChannelStub = static_cast< _ChannelWebAppStub* >(data);
471         SysTryReturn(NID_IO, pChannelStub != null, FALSE, E_SYSTEM,
472                         "[E_SYSTEM] pChannelStub is null.");
473
474         serverFd = g_io_channel_unix_get_fd(source);
475
476         clientFd = accept(serverFd,
477                                         (struct sockaddr*) &socketInfo,
478                                         &socketInfoLength);
479         SysTryReturn(NID_IO, clientFd != -1, FALSE, E_SYSTEM, "[E_SYSTEM] Failed to accept.");
480
481         // Get a http header
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)
486         {
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);
490
491                 SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Failed to recv, header length is less than 0.");
492                 goto CATCH;
493         }
494
495         SysLog(NID_IO, "recv - header length = %d", headerLength);
496         SysLog(NID_IO, "recv - header data = %s", header);
497
498         pGIOChannel = g_io_channel_unix_new(clientFd);
499         SysTryCatch(NID_IO, pGIOChannel != null, , E_SYSTEM,    "[E_SYSTEM] Failed to create GIOChannel.");
500
501         g_io_channel_set_encoding(pGIOChannel, NULL, &pGError);
502         g_io_channel_set_flags(pGIOChannel, G_IO_FLAG_NONBLOCK, &pGError);
503
504         g_io_channel_set_close_on_unref(pGIOChannel, TRUE);
505         //clientFd = -1;
506
507         // Handshake with WebApp
508         // check if header of app socket is not for websocket
509         headerData = header;
510         headerType = VerifyHttpHeaderType(headerData, headerLength);
511
512         SysLog(NID_IO, "VerifyHttpHeader, type = %d", headerType);
513
514         if (headerType == WS_NONE)
515         {
516                 SysLog(NID_IO, "Unpermitted header type");
517                 close(clientFd);
518         }
519
520         // Set the header type
521         gHeaderType = headerType;
522
523
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);
528
529         if (headerType == WS_HYBI00)
530         {
531                 SysLog(NID_IO, "WS_HYBI00");
532
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);
542
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);
549
550         }
551         else if (headerType == WS_HYBI10)
552         {
553                 SysLog(NID_IO, "WS_HYBI10");
554
555                 const char* pSecureKeyValue = soup_message_headers_get_one(
556                                 pSoupHeader, webSocketHeaderKey);
557
558                 std::string secureKey(pSecureKeyValue);
559                 secureKey.append(webSocketMagicString);
560
561                 // make Sec-WebSocket-Accept data for hybi10
562                 const std::string response = MakeHybi10Response(secureKey);
563
564                 // create response header to be sent to app
565                 std::string responseHeader = CreateResponseHeader(clientFd, pSoupHeader, response);
566
567                 // send response header
568                 SysLog(NID_IO, "Send responseHeader = %s", responseHeader.c_str());
569                 len = send(clientFd, responseHeader.c_str(), responseHeader.size(), 0);
570                 if (len < 1)
571                 {
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.");
574                         goto CATCH;
575                 }
576         }
577         else
578         {
579                 SysLog(NID_IO, "ELSE");
580         }
581
582         if (len == -1)
583         {
584                 SysLog(NID_IO, "Failed to send responseHeader");
585                 SysLog(NID_IO, "errno = %d %s", errno, strerror(errno));
586                 close(clientFd);
587                 return false;
588         }
589
590         // Parse and set appId for WebApp
591         {
592                 String tempStr;
593                 String headerString(header);
594
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);
603         }
604
605         // Check the destAppId
606         out = pChannelStub->__pChannelService->IsChannelRegistered(destAppId);
607         SysTryCatch(NID_IO, out, , E_SYSTEM, "[E_SYSTEM] Destination channel is not found.");
608
609         // Set a ClientInfo
610         key = srcAppId;
611         pChannelStub->__pClients->ContainsKey(key, out);
612         if (!out) // first connection request from this client
613         {
614                 SysLog(NID_IO, "First Connection of WebApp - AppId = %ls", srcAppId.GetPointer());
615
616                 pClientInfo = new (std::nothrow) _ClientInfo();
617
618                 pClientInfo->srcAppId = srcAppId;
619                 //pClientInfo->srcAppExecName = srcAppExecName;
620                 pClientInfo->pChannelStub = pChannelStub;
621                 //pClientInfo->clientId = clientFd;
622                 pClientInfo->key = key;
623
624                 pChannelStub->__pClients->Add(*(new String(key)), *pClientInfo);
625
626                 // Stores client info to _ChannelService
627                 SysLog(NID_IO, "Register Channel for WebApp");
628
629                 pChannelStub->__pChannelService->RegisterChannel(srcAppId, clientFd, WEBAPP_CHANNEL);
630         }
631
632         SysLog(NID_IO, "srcAppId = %ls, destAppId = %ls", srcAppId.GetPointer(), destAppId.GetPointer());
633
634         // Set the callbak
635         pChannelInfo = new (std::nothrow) _ChannelInfo;
636         SysTryCatch(NID_IO, pChannelInfo != null, , E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
637
638         pGSource = g_io_create_watch(pGIOChannel, (GIOCondition) (G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP));
639
640         g_source_set_callback(pGSource, (GSourceFunc) OnReadMessage, pChannelInfo, NULL);
641         g_source_attach(pGSource, ((_ChannelWebAppStub*)data)->__pGMainContext);
642
643         pChannelStub->__pClientGSource = pGSource;
644
645
646         // Set a ChannelInfo
647         pChannelInfo->pClientInfo = pClientInfo;
648         pChannelInfo->pGIOChannel = pGIOChannel;
649         pChannelInfo->pGSource = pGSource;
650         pChannelInfo->destAppId = destAppId;
651
652         pClientInfo->channels.push_back(pChannelInfo);
653
654
655         return true;
656
657 CATCH:
658         if (pGIOChannel != null)
659         {
660                 g_io_channel_unref(pGIOChannel);
661         }
662
663         if (clientFd != -1)
664         {
665                 close(clientFd);
666         }
667
668         return true;
669 }
670
671 gboolean
672 _ChannelWebAppStub::OnReadMessage(GIOChannel* source, GIOCondition condition, gpointer data)
673 {
674         SysLog(NID_IO, "Callback");
675
676         gboolean ret = FALSE;
677
678         _ChannelInfo* pChannelInfo = (_ChannelInfo*) data;
679         _ClientInfo* pClientInfo = pChannelInfo->pClientInfo;
680         _ChannelWebAppStub* pChannelStub = (_ChannelWebAppStub*) pClientInfo->pChannelStub;
681         ret = pChannelStub->HandleReceivedMessage(source, condition, data);
682
683         return ret;
684 }
685
686 gboolean
687 _ChannelWebAppStub::HandleReceivedMessage(GIOChannel* source, GIOCondition condition, gpointer data)
688 {
689         result r = E_SUCCESS;
690         GError* pGError = null;
691         int clientFd = g_io_channel_unix_get_fd(source);
692
693         SysLog(NID_IO, "HandleMessage - client = %d", clientFd);
694
695         _ChannelInfo* pChannelInfo = (_ChannelInfo*) data;
696         _ClientInfo* pClientInfo = pChannelInfo->pClientInfo;
697         _ChannelWebAppStub* pChannelStub = (_ChannelWebAppStub*) pClientInfo->pChannelStub;
698
699         if (condition & G_IO_HUP)
700         {
701                 SysLog(NID_IO, "G_IO_HUP - connection closed");
702
703                 g_io_channel_shutdown(source, FALSE, &pGError);
704
705                 for (unsigned int i = 0; i < pClientInfo->channels.size(); i++)
706                 {
707                         if (pChannelInfo == pClientInfo->channels[i])
708                         {
709                                 pClientInfo->channels.erase(pClientInfo->channels.begin() + i);
710
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;
714                                 delete pChannelInfo;
715
716                                 break;
717                         }
718                 }
719
720                 if (pClientInfo->channels.size() == 0)
721                 {
722                         SysLog(NID_IO, "All connections of client(%ls) are closed. delete client info", pClientInfo->srcAppId.GetPointer());
723
724                         String key = pClientInfo->srcAppId;
725                         __pClients->Remove(key, false);
726
727                         delete pClientInfo;
728
729                         pChannelStub->__pChannelService->UnregisterChannel(clientFd);
730                 }
731
732                 return FALSE;
733         }
734         else if (condition & G_IO_IN)
735         {
736                 SysLog(NID_IO, "G_IO_IN");
737
738                 unique_ptr<char[]> pBuffer(new char[MAX_BUFFER_LENGTH]);
739                 int len = recv(clientFd, (char *)pBuffer.get(), MAX_BUFFER_LENGTH, 0);
740                 if (len < 0)
741                 {
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());
745
746                         SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Failed to recv, length is less than 0.");
747
748                         return FALSE;
749                 }
750                 else if (len == 0)
751                 {
752                         SysLog(NID_IO, "The peer has performed an orderly shutdown, recv = %d", len);
753
754                         g_io_channel_shutdown(source, FALSE, &pGError);
755
756                         for (unsigned int i = 0; i < pClientInfo->channels.size(); i++)
757                         {
758                                 if (pChannelInfo == pClientInfo->channels[i])
759                                 {
760                                         pClientInfo->channels.erase(pClientInfo->channels.begin() + i);
761
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;
765                                         delete pChannelInfo;
766
767                                         break;
768                                 }
769                         }
770
771                         if (pClientInfo->channels.size() == 0)
772                         {
773                                 SysLog(NID_IO, "All connections of client(%ls) are closed. delete client info", pClientInfo->srcAppId.GetPointer());
774
775                                 String key = pClientInfo->srcAppId;
776                                 __pClients->Remove(key, false);
777
778                                 delete pClientInfo;
779
780                                 pChannelStub->__pChannelService->UnregisterChannel(clientFd);
781                         }
782
783                         return FALSE;
784                 }
785
786                 if (gHeaderType == WS_HYBI00)
787                 {
788                         // Not supported because of old websocket protocol
789                         SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Not supported protocol.");
790
791                         return FALSE;
792                 }
793                 else if (gHeaderType == WS_HYBI10)
794                 {
795                         SysLog(NID_IO,"WS_HYBI10 is supported, received data: %s (%d)", pBuffer.get(), len);
796
797                         // Current webkit of tizen support
798                         _WebSocketMessage message;
799                         int ret = 0;
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!");
802
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!");
805
806                         message.ConsoleMessage();
807
808                         // do something for opcode or custom protocol of payload
809                         if (message.m_header.factors.opcode == OPCODE_CONNECTION_CLOSE)
810                         {
811                                 SysLog(NID_IO,"OPCODE_CONNECTION_CLOSE with clientFd: %d", clientFd);
812
813                                 g_io_channel_shutdown(source, FALSE, &pGError);
814
815                                 for (unsigned int i = 0; i < pClientInfo->channels.size(); i++)
816                                 {
817                                         if (pChannelInfo == pClientInfo->channels[i])
818                                         {
819                                                 pClientInfo->channels.erase(pClientInfo->channels.begin() + i);
820
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;
824                                                 delete pChannelInfo;
825
826                                                 break;
827                                         }
828                                 }
829
830                                 if (pClientInfo->channels.size() == 0)
831                                 {
832                                         SysLog(NID_IO, "All connections of client(%ls) are closed. delete client info", pClientInfo->srcAppId.GetPointer());
833
834                                         String key = pClientInfo->srcAppId;
835                                         __pClients->Remove(key, false);
836
837                                         delete pClientInfo;
838
839                                         pChannelStub->__pChannelService->UnregisterChannel(clientFd);
840                                 }
841
842                                 return FALSE;
843                         }
844                         else if (message.m_header.factors.opcode == OPCODE_TEXT_MESSAGE)
845                         {
846                                 // Parse the data
847                                 RequestId reqId = 0;
848
849                                 ArrayList list;
850                                 list.Construct();
851
852                                 list.Add(*(new String((char*)message.m_payload)));
853
854                                 SysLog(NID_IO, "srcAppId = %ls, destAppId = %ls", pClientInfo->srcAppId.GetPointer(), pChannelInfo->destAppId.GetPointer());
855
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.");
859
860                                 list.RemoveAll(true);
861                         }
862                         else
863                         {
864                                 // Not yet supported opcode
865                                 SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Not supported Opcode.");
866
867                                 return FALSE;
868                         }
869                 }
870                 else
871                 {
872                         SysLogException(NID_IO, E_SYSTEM, "[E_SYSTEM] Not supported protocol.");
873
874                         return FALSE;
875                 }
876
877         }
878         else
879         {
880                 SysLog(NID_IO, "G_IO else");
881                 return FALSE;
882         }
883
884         return TRUE;
885 }
886
887 WebSocketType
888 _ChannelWebAppStub::VerifyHttpHeaderType(std::string header, int headerLength)
889 {
890         // parse http header
891         SoupMessageHeaders* pSoupHeader =
892                 soup_message_headers_new(SOUP_MESSAGE_HEADERS_REQUEST);
893         if (!soup_headers_parse(header.c_str(), headerLength, pSoupHeader))
894         {
895                 return WS_NONE;
896         }
897
898         WebSocketType headerType;
899         const char* pHeaderValue =
900                 soup_message_headers_get_one(pSoupHeader, webSocketHeaderId);
901
902         if (!pHeaderValue)
903         {
904                 SysLog(NID_IO, "Not for web socket header.");
905                 return WS_NONE;
906         }
907
908         if (strcmp(pHeaderValue, webSocketHeaderIdHybi00) == 0)
909         {
910                 headerType = WS_HYBI00;
911         }
912         if (strcmp(pHeaderValue, webSocketHeaderIdHybi10) == 0)
913         {
914                 headerType = WS_HYBI10;
915         }
916         else
917         {
918                 headerType = WS_NONE;
919         }
920
921         return headerType;
922 }
923
924 std::string
925 _ChannelWebAppStub::CreateResponseHeader(int appSocket, SoupMessageHeaders *header,
926                 const std::string& response)
927 {
928         std::string responseHeader;
929
930         //if (m_appSockets[appSocket] == WS_HYBI00) {
931         if (gHeaderType == WS_HYBI00)
932         {
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) {
945         }
946         else if (gHeaderType == WS_HYBI10)
947         {
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
956         }
957         else
958         {
959                 responseHeader = std::string();
960         }
961
962         return responseHeader;
963 }
964
965 std::string
966 _ChannelWebAppStub::MakeHybi00Response(uint32_t first, uint32_t second, uint8_t* third)
967 {
968         SysAssertf(third != null, "The input parameter third should not be null.");
969
970         if (sizeof(third) != _CHALLENGE_NUMBER_SIZE)
971         {
972                 SysLog(NID_IO, "Invalid third argument.");
973                 return NULL;
974         }
975
976         bool result = false;
977         uint8_t temp[_CHALLENGE_RESPONSE_SIZE];
978         result = AppendChallengeNumber(first, &temp[0]);
979         if (!result)
980         {
981                 SysLog(NID_IO, "Failed to set challenge number.");
982                 return NULL;
983         }
984
985         result = AppendChallengeNumber(second, &temp[4]);
986         if (!result)
987         {
988                 SysLog(NID_IO, "Failed to set challenge number.");
989                 return NULL;
990         }
991
992         memcpy(temp + 8, third, _CHALLENGE_THIRD_INFO_SIZE);
993         SysLog(NID_IO,"Challenge Response before md5 : %s", reinterpret_cast<char *>(temp));
994
995         // set MD5 hash
996         unsigned char hash[16];
997         MD5((unsigned char*) temp, _CHALLENGE_RESPONSE_SIZE, hash);
998
999         return std::string(reinterpret_cast<const char*>(hash));
1000 }
1001
1002 std::string
1003 _ChannelWebAppStub::MakeHybi10Response(std::string& secureAccept)
1004 {
1005         if (secureAccept.empty())
1006         {
1007                 SysLog(NID_IO, "Invalid argruments");
1008                 return NULL;
1009         }
1010
1011         unsigned char hash[20];
1012         SHA1(reinterpret_cast<const unsigned char*>(secureAccept.c_str()),
1013                         secureAccept.size(),
1014                         hash);
1015
1016         return std::string(EncodeBase64(hash, 20));
1017 }
1018
1019 bool
1020 _ChannelWebAppStub::AppendChallengeNumber(uint32_t number, unsigned char *response)
1021 {
1022         if (!response)
1023         {
1024                 SysLog(NID_IO, "Invalid response string");
1025                 return false;
1026         }
1027
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++)
1031         {
1032                 *pIdx = 0xff & number;
1033                 pIdx--;
1034                 number >>= 8;
1035         }
1036
1037         return true;
1038 }
1039
1040 unsigned int
1041 _ChannelWebAppStub::ExtractChallengeNumber(const char* keyString)
1042 {
1043         if (!keyString)
1044         {
1045                 SysLog(NID_IO, "Invalid secure key");
1046                 return 0;
1047         }
1048
1049         int space = 0;
1050         std::string digits;
1051         std::string secureKey(keyString);
1052         std::string::iterator it;
1053
1054         for (it = secureKey.begin(); it < secureKey.end(); it++)
1055         {
1056                 if (*it == ' ')
1057                 {
1058                         space++;
1059                 }
1060                 else if ((*it >= '0') && (*it <= '9'))
1061                 {
1062                         digits.insert(digits.end(), 1, *it);
1063                 }
1064         }
1065
1066         std::istringstream stream(digits);
1067         unsigned int numFromDigits = 0;
1068         stream >> numFromDigits;
1069
1070         return space ? (numFromDigits / space) : numFromDigits;
1071 }
1072
1073 char*
1074 _ChannelWebAppStub::EncodeBase64(unsigned char *string, int len)
1075 {
1076         BIO* pBmem = null;
1077         BIO* pB64 = null;
1078         BUF_MEM* pBptr = null;
1079
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);
1084         BIO_flush(pB64);
1085         BIO_get_mem_ptr(pB64, &pBptr);
1086
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;
1091
1092         BIO_free_all(pB64);
1093         return pBuff;
1094 }
1095
1096 bool
1097 _ChannelWebAppStub::SendResponse(int clientId, const ArrayList& args)
1098 {
1099         unique_ptr<char[]> pStr(_StringConverter::CopyToCharArrayN(*((String*)args.GetAt(0))));
1100
1101         SysLog(NID_IO, "clientId = %d, data = %s", clientId, pStr.get());
1102
1103         string response;
1104         string payload(pStr.get());
1105
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));
1109
1110         SysLog(NID_IO, "response = %s, size = %d", response.c_str(), ret);
1111
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!");
1115
1116         ret = message.ParsePayload(reinterpret_cast<uint8_t*>(const_cast<char*>(response.c_str())), respSize);
1117         SysTryLogReturn(NID_IO, ret >= 0, false, "ParsePayloadr error!");
1118
1119         message.ConsoleMessage();
1120
1121         return true;
1122 }
1123
1124 }}
1125