Bug Fix for TIVI-1935.
[profile/ivi/ico-uxf-homescreen.git] / lib / system-controller / CicoSCServer.cpp
1 /*
2  * Copyright (c) 2013, TOYOTA MOTOR CORPORATION.
3  *
4  * This program is licensed under the terms and conditions of the
5  * Apache License, version 2.0.  The full text of the Apache License is at
6  * http://www.apache.org/licenses/LICENSE-2.0
7  *
8  */
9
10 //==========================================================================
11 /**
12  *  @file   CicoSCServer.cpp
13  *
14  *  @brief  This file implementation of CicoSCServer class
15  */
16 //==========================================================================
17
18 #include <sstream>
19 using namespace std;
20
21 #include "CicoSCServer.h"
22 #include "CicoSCCommand.h"
23 #include "CicoSCMessage.h"
24 #include "CicoLog.h"
25 #include "ico_syc_error.h"
26 #include "ico_syc_msg_cmd_def.h"
27 #include "CicoSCWindowController.h"
28 #include "CicoSCInputController.h"
29 #include "CicoSCUserManager.h"
30 #include "CicoSCUser.h"
31 #include "CicoSCResourceManager.h"
32 #include "CicoSCPolicyManager.h"
33
34 class CicoSCUwsHandler
35 {
36 public:
37     CicoSCUwsHandler()
38         : uwsContext(NULL), id(NULL), fd(-1), serviceFlag(false),
39           ecoreFdHandler(NULL), appid("") {}
40     void dump(void) const {
41         ICO_DBG("uwsContext=0x%08x fd=%d service=%s "
42                 "ecoreFdHandler=0x%08x appid=%s",
43                 uwsContext, fd, serviceFlag ? "true" : "false",
44                 ecoreFdHandler, appid.c_str());
45     }
46     struct ico_uws_context *uwsContext;
47     void*  id;
48     int    fd;
49     bool   serviceFlag;
50     Ecore_Fd_Handler *ecoreFdHandler;
51     string appid;
52 };
53
54 //==========================================================================    
55 //  private static variable
56 //==========================================================================    
57 CicoSCServer* CicoSCServer::ms_myInstance = NULL;
58
59 //--------------------------------------------------------------------------
60 /**
61  *  @brief  default constructor
62  */
63 //--------------------------------------------------------------------------
64 CicoSCServer::CicoSCServer()
65     : m_uwsContext(NULL), m_windowCtrl(NULL),
66       m_inputCtrl(NULL) , m_userMgr(NULL), m_resourceMgr(NULL)
67 {
68 }
69
70 //--------------------------------------------------------------------------
71 /**
72  *  @brief  destructor
73  */
74 //--------------------------------------------------------------------------
75 CicoSCServer::~CicoSCServer()
76 {
77     // TODO
78 }
79
80 //--------------------------------------------------------------------------
81 /**
82  *  @brief   get CicoSCServer instance
83  *
84  *  @return CicoSCServer instance
85  */
86 //--------------------------------------------------------------------------
87 CicoSCServer*
88 CicoSCServer::getInstance(void)
89 {
90     if (NULL == ms_myInstance) {
91         ms_myInstance = new CicoSCServer();
92     }
93
94     return ms_myInstance;
95 }
96
97 //--------------------------------------------------------------------------
98 /**
99  *  @brief   set window controller instance
100  *
101  *  @param [in] windowCtrl  controller instance
102  */
103 //--------------------------------------------------------------------------
104 void
105 CicoSCServer::setWindowCtrl(CicoSCWindowController *windowCtrl)
106 {
107     m_windowCtrl = windowCtrl;
108 }
109
110 //--------------------------------------------------------------------------
111 /**
112  *  @brief   set input controller instance
113  *
114  *  @param [in] inputCtrl   controller instance
115  */
116 //--------------------------------------------------------------------------
117 void
118 CicoSCServer::setInputCtrl(CicoSCInputController *inputCtrl)
119 {
120     m_inputCtrl= inputCtrl;
121 }
122
123 //--------------------------------------------------------------------------
124 /**
125  *  @brief   set user manager
126  *
127  *  @param [in] userMgr     user manager instance
128  */
129 //--------------------------------------------------------------------------
130 void
131 CicoSCServer::setUserMgr(CicoSCUserManager *userMgr)
132 {
133     m_userMgr = userMgr;
134 }
135
136 //--------------------------------------------------------------------------
137 /**
138  *  @brief   set resource manager instance
139  *
140  *  @param [in] resourceMgr resouce manager instance
141  */
142 //--------------------------------------------------------------------------
143 void
144 CicoSCServer::setResourceMgr(CicoSCResourceManager *resourceMgr)
145 {
146     m_resourceMgr = resourceMgr;
147 }
148
149 //--------------------------------------------------------------------------
150 /**
151  *  @brief   set policy manager instance
152  *
153  *  @param [in] policyMgr policy manager instance
154  */
155 //--------------------------------------------------------------------------
156 void
157 CicoSCServer::setPolicyMgr(CicoSCPolicyManager *policyMgr)
158 {
159     m_policyMgr = policyMgr;
160 }
161
162 //--------------------------------------------------------------------------
163 /**
164  *  @brief   startup server
165  *
166  *  @param [in] port        websocket port
167  *  @param [in] protocol    websocket protocol name
168  *
169  *  @return ICO_SYC_EOK on success, other on error
170  *  @retval ICO_SYC_EOK     success
171  *  @retval ICO_SYC_ENOSYS  error(connection fail)
172  */
173 //--------------------------------------------------------------------------
174 int
175 CicoSCServer::startup(int port, const char *protocol)
176 {
177     /* create uir string ":PORT" */
178     stringstream uri;
179     uri << ":" << port;
180
181     /* create context */
182     ICO_DBG("called: ico_uws_create_context(port=%s protocol=%s)",
183             uri.str().c_str(), protocol);
184     m_uwsContext = ico_uws_create_context(uri.str().c_str(), protocol);
185     if (NULL == m_uwsContext) {
186         ICO_ERR("ico_uws_create_context() failed.");
187         return ICO_SYC_ENOSYS;
188     }
189     ico_uws_service(m_uwsContext);
190
191     /* set callback */
192     int ret = ico_uws_set_event_cb(m_uwsContext, uwsReceiveEventCB,
193                                    (void *)this);
194     if (ret != ICO_UWS_ERR_NONE) {
195         ICO_ERR("ico_uws_set_event_cb() failed(%d).", ret);
196         return ICO_SYC_ENOSYS;
197     }
198     ico_uws_service(m_uwsContext);
199
200     return ICO_SYC_EOK;
201 }
202
203 //--------------------------------------------------------------------------
204 /**
205  *  @brief   add poll websocket file destructor
206  *
207  *  @param [in] handler  websocket handler
208  */
209 //--------------------------------------------------------------------------
210 void
211 CicoSCServer::addPollFd(CicoSCUwsHandler *handler)
212 {
213     ICO_DBG("CicoSCServer::addPollFd Enter(fd=%d)", handler->fd);
214     Ecore_Fd_Handler_Flags flags;
215     flags = (Ecore_Fd_Handler_Flags)(ECORE_FD_READ | ECORE_FD_ERROR);
216
217     handler->ecoreFdHandler = ecore_main_fd_handler_add(handler->fd, flags,
218                                                        ecoreFdCallback,
219                                                        this, NULL, NULL);
220
221     ICO_DBG("Enqueue uwsHandler(0x%08x)", handler);
222     m_uwsHandlerList.push_back(handler);
223
224     ICO_DBG("CicoSCServer::addPollFd Leave");
225 }
226
227 //--------------------------------------------------------------------------
228 /**
229  *  @brief   delete poll websocket file destructor
230  *
231  *  @param [in] handler  websocket handler
232  */
233 //--------------------------------------------------------------------------
234 void
235 CicoSCServer::delPollFd(CicoSCUwsHandler *handler)
236 {
237     ICO_DBG("CicoSCServer::delPollFd Enter");
238
239     ecore_main_fd_handler_del(handler->ecoreFdHandler);
240     handler->ecoreFdHandler = NULL;
241
242     list<CicoSCUwsHandler*>::iterator itr;
243     itr = m_uwsHandlerList.begin();
244     for (; itr != m_uwsHandlerList.end(); ++itr) {
245         if (*itr == handler) {
246             ICO_DBG("Dequeue uwsHandler(0x%08x)", *itr);
247             m_uwsHandlerList.erase(itr);
248             break;
249         }
250     }
251     delete handler;
252
253     ICO_DBG("CicoSCServer::delPollFd Enter");
254 }
255
256 //--------------------------------------------------------------------------
257 /**
258  *  @brief   dispatch receive message process and send message process
259  *
260  *  @param [in] handler  websocket handler
261  *
262  *  @return websocket handler instance on find, NULL on not found
263  */
264 //--------------------------------------------------------------------------
265 void
266 CicoSCServer::dispatch(const CicoSCUwsHandler *handler)
267 {
268 //    ICO_DBG("CicoSCServer::dispatch Enter(handler=0x%08x)", handler);
269
270     if (NULL == handler) {
271         ICO_WRN("handler is null");
272         ICO_DBG("CicoSCServer::dispatch Leave");
273         return;
274     }
275
276     ico_uws_service(handler->uwsContext);
277
278     // There is a possibility that after calling ico_uws_service function,
279     // the file is deleted.  Check whether handler not the disabled.
280     if (false == isExistUwsHandler(handler)) {
281         ICO_DBG("CicoSCServer::dispatch Leave");
282         return;
283     }
284
285     list<CicoSCCommand*>::iterator itr;
286     itr = m_recvCmdQueue.begin();
287     while(itr != m_recvCmdQueue.end()) {
288         ICO_DBG("Dequeue command(0x%08x)", (*itr)->cmdid);
289         CicoSCCommand *cmd = *itr;
290         itr = m_recvCmdQueue.erase(itr);
291         switch (cmd->cmdid & MSG_CMD_TYPE_MASK) {
292         case MSG_CMD_TYPE_WINCTRL:
293             //ICO_DBG("command : MSG_CMD_TYPE_WINCTRL");
294             m_windowCtrl->handleCommand(cmd);
295             break;
296         case MSG_CMD_TYPE_INPUTCTRL:
297             //ICO_DBG("command : MSG_CMD_TYPE_INPUTCTRL");
298             m_inputCtrl->handleCommand(cmd);
299             break;
300         case MSG_CMD_TYPE_USERMGR:
301             //ICO_DBG("command : MSG_CMD_TYPE_USERMGR");
302             m_userMgr->handleCommand(cmd);
303             break;
304         case MSG_CMD_TYPE_RESOURCEMGR:
305             //ICO_DBG("command : MSG_CMD_TYPE_RESOURCEMGR");
306             m_resourceMgr->handleCommand(*cmd);
307             break;
308         case MSG_CMD_TYPE_INPUTDEVSETTING:
309             //ICO_DBG("command : MSG_CMD_TYPE_INPUTDEVSETTING");
310             m_inputCtrl->handleCommand(cmd);
311             break;
312         default:
313             ICO_WRN("command: Unknown type");
314             break;
315         }
316         delete cmd;
317     }
318
319     if (NULL == handler->ecoreFdHandler) {
320         ICO_ERR("ecoreFdHandler is null");
321         ICO_DBG("CicoSCServer::dispatch Leave");
322         return;
323     }
324
325     Eina_Bool flag = ecore_main_fd_handler_active_get(handler->ecoreFdHandler,
326                                                       ECORE_FD_WRITE);
327     if (EINA_TRUE == flag) {
328 //        ICO_DBG("start send message");
329         list<CicoSCMessage*>::iterator send_itr;
330         send_itr = m_sendMsgQueue.begin();
331         while (send_itr != m_sendMsgQueue.end()) {
332 //            ICO_DBG("m_sendMsgQueue.size=%d", m_sendMsgQueue.size());
333             CicoSCMessage* msg = *send_itr;
334             CicoSCUwsHandler *sendHandler = findUwsHandler(msg->getSendToAppid());
335             if (handler != sendHandler) {
336                 ++send_itr;
337                 continue;
338             }
339             send_itr = m_sendMsgQueue.erase(send_itr);
340             ICO_DBG("Dequeue Message(id=%d)", msg->getId());
341             if ((NULL != sendHandler) && (true == sendHandler->serviceFlag)) {
342                 ICO_DBG("<<<SEND appid=%s id=0x%08x msg=%s",
343                         sendHandler->appid.c_str(), sendHandler->id, msg->getData());
344 //                ICO_DBG("called: ico_usw_send called(context=0x%08x id=0x%08x)",
345 //                        sendHandler->uwsContext, sendHandler->id);
346                 ico_uws_send(sendHandler->uwsContext, sendHandler->id,
347                              (unsigned char *)msg->getData(),
348                              strlen(msg->getData()));
349
350                 delete msg;
351
352                 usleep(200);
353             }
354         }
355
356         Ecore_Fd_Handler_Flags flags;;
357         flags = (Ecore_Fd_Handler_Flags)(ECORE_FD_READ | ECORE_FD_ERROR);
358
359         ecore_main_fd_handler_active_set(handler->ecoreFdHandler, flags);
360     }
361
362 //    ICO_DBG("CicoSCServer::dispatch Leave");
363 }
364
365 //--------------------------------------------------------------------------
366 /**
367  *  @brief   send message to application client
368  *
369  *  @param [in] appid   application id of destination
370  *  @param [in] msg     message
371  *
372  *  @return ICO_SYC_EOK on success, other on error
373  */
374 //--------------------------------------------------------------------------
375 int
376 CicoSCServer::sendMessage(const string & appid, CicoSCMessage* msg)
377 {
378     ICO_DBG("CicoSCServer::sendMessage Enter(appid=%s, msg=%s)",
379             appid.c_str(), msg->getData());
380
381     msg->setSendToAppid(appid);
382     ICO_DBG("Enqueue Message(id=%d)", msg->getId());
383     m_sendMsgQueue.push_back(msg);
384
385     CicoSCUwsHandler *handler = findUwsHandler(appid);
386     if (NULL != handler) {
387         Ecore_Fd_Handler_Flags flags;
388         flags = (Ecore_Fd_Handler_Flags)(ECORE_FD_READ  |
389                                          ECORE_FD_WRITE |
390                                          ECORE_FD_ERROR);
391
392         ecore_main_fd_handler_active_set(handler->ecoreFdHandler, flags);
393
394         dispatch(handler);
395     }
396
397     ICO_DBG("CicoSCServer::sendMessage Leave(EOK)");
398     return ICO_SYC_EOK;
399 }
400
401 //--------------------------------------------------------------------------
402 /**
403  *  @brief   send message to homescreen
404  *
405  *  @param [in] msg     message
406  *
407  *  @return ICO_SYC_EOK on success, other on error
408  */
409 //--------------------------------------------------------------------------
410 int
411 CicoSCServer::sendMessageToHomeScreen(CicoSCMessage* msg)
412 {
413     const CicoSCUser *loginUser = m_userMgr->getLoginUser();
414     if (NULL == loginUser) {
415         ICO_WRN("homescreen unknown");
416         return ICO_SYC_ENOENT;
417     }
418     return sendMessage(loginUser->homescreen, msg);
419 }
420
421 //--------------------------------------------------------------------------
422 /*
423  *  @brief  websocket utility callback function
424  *
425  *  @param [in] context     context
426  *  @param [in] event       event kinds
427  *  @param [in] id          client id
428  *  @param [in] detail      event detail
429  *  @param [in] data        user data
430  */
431 //--------------------------------------------------------------------------
432 void
433 CicoSCServer::uwsReceiveEventCB(const struct ico_uws_context *context,
434                                 const ico_uws_evt_e event,
435                                 const void *id,
436                                 const ico_uws_detail *detail,
437                                 void *user_data)
438 {
439     if (NULL == user_data) {
440         ICO_ERR("user_data is NULL");
441         return;
442     }
443
444     CicoSCServer* server = static_cast<CicoSCServer*>(user_data);
445     server->receiveEventCB(context, event, id, detail, user_data);
446 }
447
448 //--------------------------------------------------------------------------
449 /**
450  *  @brief   ecore file destructor callback fucntion
451  *
452  *  @param [in] data        user data
453  *  @param [in] handler     ecore file destructor handler
454  *
455  *  @return ECORE_CALLBACK_RENEW on retry , ECORE_CALLBACK_CANCEL on cancel
456  */
457 //--------------------------------------------------------------------------
458 Eina_Bool
459 CicoSCServer::ecoreFdCallback(void *data, Ecore_Fd_Handler *ecoreFdhandler)
460 {
461 //    ICO_DBG("CicoSCServer::ecoreFdCallback Enter");
462
463     CicoSCUwsHandler *handler = NULL;
464     handler =  static_cast<CicoSCServer*>(data)->findUwsHandler(ecoreFdhandler);
465     if (NULL != handler) {
466         static_cast<CicoSCServer*>(data)->dispatch(handler);
467     }
468
469 //    ICO_DBG("CicoSCServer::ecoreFdCallback Leave");
470     return ECORE_CALLBACK_RENEW;
471 }
472
473 //--------------------------------------------------------------------------
474 /**
475  *  @brief   websocket callback function
476  *
477  *  @param [in] context     websocket context
478  *  @param [in] event       changed event
479  *  @param [in] id          source applicatin id
480  *  @param [in] detail      event detail information
481  *  @param [in] user_data   user data
482  */
483 //--------------------------------------------------------------------------
484 void
485 CicoSCServer::receiveEventCB(const struct ico_uws_context *context,
486                              const ico_uws_evt_e          event,
487                              const void                   *id,
488                              const ico_uws_detail         *detail,
489                              void                         *user_data)
490 {
491 //    ICO_DBG("CicoSCServer::receiveEventCB Enter");
492
493     // find handler
494     CicoSCUwsHandler *handler = findUwsHandler(context, id);
495     // If not found handler, create new handler
496     if (NULL == handler) {
497         handler = new CicoSCUwsHandler();
498         handler->uwsContext = (struct ico_uws_context*)context;
499         handler->id = (void*)(id);
500         handler->serviceFlag = false;
501     }
502
503     switch (event) {
504     case ICO_UWS_EVT_OPEN:
505         ICO_DBG(">>>RECV ICO_UWS_EVT_OPEN(id=0x%08x)", (int)id); 
506         break;
507     case ICO_UWS_EVT_CLOSE:
508         ICO_DBG(">>>RECV ICO_UWS_EVT_CLOSE(id=0x%08x)", (int)id);
509         break;
510     case ICO_UWS_EVT_RECEIVE:
511     {
512         ICO_DBG(">>>RECV ICO_UWS_EVT_RECEIVE(id=0x%08x, msg=%s, len=%d)", 
513                 (int)id, (char *)detail->_ico_uws_message.recv_data,
514                 detail->_ico_uws_message.recv_len);
515
516         // convert message to command
517         CicoSCCommand *cmd = new CicoSCCommand();
518         cmd->parseMessage((const char*)detail->_ico_uws_message.recv_data);
519
520         // update handler appid
521         if (cmd->cmdid == MSG_CMD_SEND_APPID) {
522             if (0 == cmd->appid.length()) {
523                 ICO_WRN("command argument invalid appid null");
524                 break;
525             }
526             handler->appid = cmd->appid;
527             handler->serviceFlag = true;
528             ICO_DBG("handler.appid=%s", handler->appid.c_str());
529
530             Ecore_Fd_Handler_Flags flags;
531             flags = (Ecore_Fd_Handler_Flags)(ECORE_FD_READ  |
532                                              ECORE_FD_WRITE |
533                                              ECORE_FD_ERROR);
534
535             ecore_main_fd_handler_active_set(handler->ecoreFdHandler, flags);
536
537             notifyConnected(handler->appid);
538             break;
539         }
540         
541         // Enqueue command
542         ICO_DBG("Enqueue command(0x%08x)", cmd->cmdid);
543         m_recvCmdQueue.push_back(cmd);
544         break;
545     }
546     case ICO_UWS_EVT_ERROR:
547         ICO_DBG(">>>RECV ICO_UWS_EVT_ERROR(id=0x%08x, err=%d)", 
548                 (int)id, detail->_ico_uws_error.code);
549         break;
550     case ICO_UWS_EVT_ADD_FD:
551         ICO_DBG(">>>RECV ICO_UWS_EVT_ADD_FD(id=0x%08x, fd=%d)",
552                     (int)id, detail->_ico_uws_fd.fd);
553         handler->fd = detail->_ico_uws_fd.fd;
554         addPollFd(handler);
555         break;
556     case ICO_UWS_EVT_DEL_FD:
557         ICO_DBG(">>>RECV ICO_UWS_EVT_DEL_FD(id=0x%08x, fd=%d)",
558                     (int)id, detail->_ico_uws_fd.fd);
559         delPollFd(handler);
560         break;
561     default:
562         break;
563     }
564 //    ICO_DBG("CicoSCServer::receiveEventCB Leave");
565 }
566
567 //--------------------------------------------------------------------------
568 /**
569  *  @brief   find websocket handler by context and id
570  *
571  *  @param [in] context     websocket context
572  *  @param [in] id          id
573  *
574  *  @return websocket handler instance on find, NULL on not found
575  */
576 //--------------------------------------------------------------------------
577 CicoSCUwsHandler*
578 CicoSCServer::findUwsHandler(const struct ico_uws_context *context,
579                              const void                   *id)
580 {
581     list<CicoSCUwsHandler*>::iterator itr;
582     itr = m_uwsHandlerList.begin();
583     for (; itr != m_uwsHandlerList.end(); ++itr) {
584 //        ICO_DBG("handler->context=%p handler->id=%p context=%p id=%p",
585 //                (*itr)->uwsContext, (*itr)->id, context, id);
586         if (((*itr)->uwsContext == context) &&
587             ((*itr)->id == id)) {
588             return *itr;
589         }
590     }
591     return NULL;
592 }
593
594 //--------------------------------------------------------------------------
595 /**
596  *  @brief   find websocket handler by ecore file destructor handler
597  *
598  *  @param [in] ecoreFdHandler  ecore file destructor handler
599  *
600  *  @return websocket handler instance on find, NULL on not found
601  */
602 //--------------------------------------------------------------------------
603 CicoSCUwsHandler*
604 CicoSCServer::findUwsHandler(const Ecore_Fd_Handler *ecoreFdHandler)
605 {
606     list<CicoSCUwsHandler*>::iterator itr;
607     itr = m_uwsHandlerList.begin();
608     for (; itr != m_uwsHandlerList.end(); ++itr) {
609         if ((*itr)->ecoreFdHandler == ecoreFdHandler) {
610             return *itr;
611         }
612     }
613     return NULL;
614 }
615
616 //--------------------------------------------------------------------------
617 /**
618  *  @brief   find websocket handler by appid
619  *
620  *  @param [in] addid   application id
621  *
622  *  @return websocket handler instance on find, NULL on not found
623  */
624 //--------------------------------------------------------------------------
625 CicoSCUwsHandler*
626 CicoSCServer::findUwsHandler(const string & appid)
627 {
628     list<CicoSCUwsHandler*>::iterator itr;
629     itr = m_uwsHandlerList.begin();
630     for (; itr != m_uwsHandlerList.end(); ++itr) {
631 //        ICO_DBG("handler->id=%p handler->appid=%s appid=%s",
632 //                (*itr)->id, (*itr)->appid.c_str(), appid.c_str());
633         if ((*itr)->appid == appid) {
634             return *itr;
635         }
636     }
637     return NULL;
638 }
639
640 //--------------------------------------------------------------------------
641 /**
642  *  @brief   find websocket handler by appid
643  *
644  *  @param [in] handler     websocket handler instance
645  *
646  *  @return true on exist, false on not exist
647  */
648 //--------------------------------------------------------------------------
649 bool
650 CicoSCServer::isExistUwsHandler(const CicoSCUwsHandler *handler)
651 {   
652     list<CicoSCUwsHandler*>::iterator itr;
653     itr = m_uwsHandlerList.begin();
654     for (; itr != m_uwsHandlerList.end(); ++itr) {
655         if (*itr == handler) {
656             return true;
657         }
658     }
659     return false;
660 }
661
662 //--------------------------------------------------------------------------
663 /**
664  *  @brief  notify information to homescreen on connected
665  *
666  *  @param [in] appid   application id
667  */
668 //--------------------------------------------------------------------------
669 void
670 CicoSCServer::notifyConnected(const std::string & appid)
671 {
672     const CicoSCUser *loginUser = m_userMgr->getLoginUser();
673     if (NULL == loginUser) {
674         ICO_WRN("homescreen unknown");
675         return;
676     }
677
678     // if appid equal homescreen
679     if (0 == loginUser->homescreen.compare(appid)) {
680         if (NULL != m_policyMgr) {
681             m_policyMgr->notifyConnected(appid);
682         }
683     }
684 }
685 // vim:set expandtab ts=4 sw=4: