d2e44e71e381d963720aed6a3c1db28322119189
[profile/ivi/ico-uxf-homescreen.git] / ico-app-framework / ico_apf_communication.c
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  * @brief   client library for communicate to AppsController in HomeScreen
11  *
12  * @date    Feb-28-2013
13  */
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <unistd.h>
18 #include <getopt.h>
19 #include <string.h>
20 #include <sys/time.h>
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23
24 #include <libwebsockets.h>
25 #include "ico_apf_private.h"
26 #include "ico_uxf_conf.h"
27
28 /*==============================================================================*/
29 /* define static function prototype                                             */
30 /*==============================================================================*/
31 static ico_apf_com_handle_t *ico_apf_alloc_handle(void);
32 static int ico_apf_com_connect(ico_apf_com_handle_t *handle);
33 static int ico_apf_com_realsend(ico_apf_com_handle_t *handle,
34                                 ico_apf_com_buffer_t *msg);
35 static int ico_apf_callback_http(struct libwebsocket_context *context,
36                                  struct libwebsocket *wsi,
37                                  enum libwebsocket_callback_reasons reason,
38                                  void *user, void *in, size_t len);
39 static int ico_apf_callback_websock(struct libwebsocket_context *this,
40                                     struct libwebsocket *wsi,
41                                     enum libwebsocket_callback_reasons reason,
42                                     void *user, void *in, size_t len);
43 static void ico_apf_put_recvmsg(const int cmd, const int res, const int pid,
44                                 const char *appid, char *msg, const int len,
45                                 ico_apf_com_handle_t *handle);
46 static int ico_apf_poll_fd_add(const int fd, const int flag);
47 static void ico_apf_poll_fd_del(const int fd);
48 static void ico_apf_poll_write_event(ico_apf_com_handle_t *handle, const int write);
49
50 /*==============================================================================*/
51 /* variable & table                                                             */
52 /*==============================================================================*/
53 /* variable that control program name in Linux  */
54 extern const char *program_invocation_name;
55
56 /* application framework control handle */
57 static struct libwebsocket_context  *global_lwscontext = NULL;
58 static ico_apf_com_handle_t *handles = NULL;
59 static ico_apf_com_handle_t *freehandles = NULL;
60
61 /* file descriptor controll table       */
62 static ico_apf_com_poll_t       *com_polls = NULL;
63 static ico_apf_com_poll_t       *freecom_polls = NULL;
64 static ico_apf_com_pollfd_cb   ico_apf_pollfd_func = NULL;
65
66 /* global user listener                 */
67 static ico_apf_com_eventlistener    global_listener = NULL;
68 static void                         *global_user_data = NULL;
69
70 /* flag for callback from libwebsockets */
71 static int      lws_callbacked = 0;
72
73 /* libwebsockets's protocol number      */
74 enum appsctl_protocols {
75     PROTOCOL_HTTP,                      /* HTTP handshake(Certainly required)   */
76     PROTOCOL_APPSCONTROLLER,            /* AppsController protocol              */
77     PROTOCOL_APPSEND                    /* everytime means final                */
78 };
79 enum soundmgr_protocols {
80     PROTOCOL_SOUNDMGR,                  /* Multi Sound Manager  protocol        */
81     PROTOCOL_SOUNDEND                   /* everytime means final                */
82 };
83
84 /* list of libwebsockets protocol for AppsController        */
85 static struct libwebsocket_protocols apps_protocols[] = {
86                                         /* HTTP handshake(Certainly required)   */
87     { "http_only", ico_apf_callback_http, 0 },
88                                         /* callback from websocket to appscontroller*/
89     { ICO_PROTOCOL_APPSCONTROLLER, ico_apf_callback_websock, sizeof(void *) },
90     { NULL, NULL, 0 }                   /* everytime means final                */
91 };
92
93 /* list of libwebsockets protocol for pulse-audio plugin    */
94 static struct libwebsocket_protocols sound_protocols[] = {
95                                         /* callback from websocket to soundmanager*/
96     { ICO_PROTOCOL_MULTISOUNDMANAGER, ico_apf_callback_websock, sizeof(void *) },
97     { NULL, NULL, 0 }                   /* everytime means final                */
98 };
99
100 /* command/event string                 */
101 const char  *ico_apf_cmd_table[] = {
102     ICO_APF_SRESOURCE_STATE_ACQUIRED,       /* acquired         */
103     ICO_APF_SRESOURCE_STATE_DEPRIVED,       /* deprived         */
104     ICO_APF_SRESOURCE_STATE_WAITTING,       /* waitting         */
105     ICO_APF_SRESOURCE_STATE_RELEASED,       /* released         */
106
107     ICO_APF_SRESOURCE_COMMAND_GET,          /* get command      */
108     ICO_APF_SRESOURCE_COMMAND_RELEASE,      /* release command  */
109     ICO_APF_SRESOURCE_COMMAND_ADD,          /* add command      */
110     ICO_APF_SRESOURCE_COMMAND_CHANGE,       /* change command   */
111     ICO_APF_SRESOURCE_COMMAND_DELETE,       /* delete command   */
112
113     ICO_APF_SRESOURCE_REPLY_OK,             /* OK reply         */
114     ICO_APF_SRESOURCE_REPLY_NG,             /* NG reply         */
115     ICO_APF_SRESOURCE_STATE_CONNECTED,      /* connected        */
116     ICO_APF_SRESOURCE_STATE_DISCONNECTED    /* disconnected     */
117 };
118 const char  *ico_apf_res_table[] = {
119     ICO_APF_SRESID_BASIC_SCREEN,            /* basic screen     */
120     ICO_APF_SRESID_INT_SCREEN,              /* interrupt screen */
121     ICO_APF_SRESID_ON_SCREEN,               /* onscreeen        */
122     ICO_APF_SRESID_BASIC_SOUND,             /* basic sound      */
123     ICO_APF_SRESID_INT_SOUND,               /* interrupt sound  */
124     ICO_APF_SRESID_INPUT_DEV                /* input device     */
125 };
126 const char  *ico_apf_sound_table[] = {
127     ICO_APF_SSOUND_COMMAND_MUTEON,          /* mute on          */
128     ICO_APF_SSOUND_COMMAND_MUTEOFF,         /* mute off         */
129     ICO_APF_SSOUND_COMMAND_CANCEL,          /* cancel           */
130     ICO_APF_SSOUND_COMMAND_GETLIST,         /* get stream list  */
131     ICO_APF_SSOUND_COMMAND_FRESH,           /* fresh            */
132     ICO_APF_SSOUND_COMMAND_ALLMUTEON,       /* mute set all stream*/
133     ICO_APF_SSOUND_COMMAND_ALLMUTEOFF,      /* mute reset all stream*/
134     ICO_APF_SSOUND_EVENT_NEW,               /* created new stream*/
135     ICO_APF_SSOUND_EVENT_FREE,              /* destoryed stream */
136     ICO_APF_SSOUND_REPLY_LIST               /* reply of stream list*/
137 };
138
139 /*--------------------------------------------------------------------------*/
140 /**
141  * @brief   ico_apf_com_init_client
142  *          This function connects to AppsController in HomeScreen.
143  *          If you use AppsController's function, you must call this function.
144  *
145  * @param[in]   uri                 connection URI, NULL is host myself
146  * @param[in]   type                connection type
147  * @return      handle address
148  * @retval      handle address      success
149  * @retval      NULL                error(failed connect AppsController)
150  */
151 /*--------------------------------------------------------------------------*/
152 ico_apf_com_handle_t *
153 ico_apf_com_init_client(const char *uri, const int type)
154 {
155     int i;
156     int port;
157     char* address;
158     ico_apf_com_poll_t *p;
159     ico_apf_com_handle_t *handle;
160     Ico_Uxf_Sys_Config *sysconf;
161     Ico_Uxf_Sys_Config *ifsysconf = (Ico_Uxf_Sys_Config *)0xffffffff;
162     char *port_env;
163     char *host_env;
164
165     apfw_trace("ico_apf_com_init_client: Enter(%s,%d)",
166                 uri ? uri : "(NULL)", type);
167
168     ifsysconf = (Ico_Uxf_Sys_Config *)ico_uxf_ifGetSysConfig();
169
170     if (ifsysconf)  {
171         /* Another module already reads config file                             */
172         /* In this case, you don't release sysconf at finished this function.   */
173         sysconf = (Ico_Uxf_Sys_Config *)ifsysconf;
174     }
175     else    {
176         /* never read a system config                   */
177         sysconf = (Ico_Uxf_Sys_Config *)ico_uxf_getSysConfig();
178     }
179     if (!sysconf)   {
180         apfw_error("ico_apf_com_init_client: Leave(can not read configuration files)");
181         return NULL;
182     }
183
184     /* If URI is host name, find address from config.   */
185     /* If node is a null character string, it regards NULL. */
186     Ico_Uxf_conf_host *phost =
187         (Ico_Uxf_conf_host *) ico_uxf_getSysHostById(ico_uxf_getSysHostByName(uri));
188     if (phost)  {
189         address = phost->address;
190     }
191     else    {
192         /* If don't find host name from config, regards ipaddress is set as node.*/
193         address = (char *)uri;
194     }
195
196     /* environment variable for port & host */
197     if (type == ICO_APF_COM_TYPE_APPSCTL)   {
198         port = sysconf->misc.appscontrollerport;
199         port_env = getenv("ICO_APF_APPSCTL_PORT");
200         host_env = getenv("ICO_APF_APPSCTL_HOST");
201     }
202     else    {
203         port = sysconf->misc.soundpluginport;
204         port_env = getenv("ICO_APF_SOUNDMGR_PORT");
205         host_env = getenv("ICO_APF_SOUNDMGR_HOST");
206     }
207     if (port_env) {
208         i = atoi(port_env);
209         if (i > 0)  port = i;
210     }
211     if (host_env)   {
212         address = host_env;
213     }
214
215     /* get a port number from system configuration(system/system.conf)  */
216     apfw_trace("ico_apf_com_init_client: connect Host=%s Port=%d", address, port);
217
218     handle = handles;
219     while (handle)  {
220         if ((strcmp(handle->ip, address) == 0) &&
221             (handle->port == port) && (handle->type == type))   {
222             break;
223         }
224         handle = handle->next;
225     }
226
227     if (handle) {
228         apfw_trace("ico_apf_com_init_client: Leave(Connected)");
229         return handle;
230     }
231
232     handle = ico_apf_alloc_handle();
233     if (! handle)   {
234         apfw_trace("ico_apf_com_init_client: Leave(No Memory)");
235         return NULL;
236     }
237
238     handle->type = type;
239     handle->port = port;
240     strncpy(handle->ip, address, ICO_APF_RESOURCE_IP_LEN-1);
241     handle->ip[ICO_APF_RESOURCE_IP_LEN-1] = 0;
242
243     /* connect to AppsController            */
244     i = ico_apf_com_connect(handle);
245
246     if (! ifsysconf)    {
247         ico_uxf_closeSysConfig();
248     }
249
250     if (i != ICO_APF_RESOURCE_E_NONE) {
251         apfw_error("ico_apf_com_init_client: Leave(RESOURCE_E_INIT_COM_FAILD)");
252         (void) ico_apf_com_term_client(handle);
253         return NULL;
254     }
255
256     /* Try to connection        */
257     ico_apf_com_dispatch(handle, 0);
258     handle->fd = libwebsocket_get_socket_fd(handle->wsi_connection);
259
260     /* add poll callback if fd is exist */
261     if (handle->fd > 0) {
262         handle->service_on = 1;
263         (void)ico_apf_poll_fd_add(handle->fd, POLLIN);
264     }
265
266     p = com_polls;
267     while (p)   {
268         if (p->fd == handle->fd)    {
269             p->apf_fd_control = (void *)handle;
270             handle->poll = p;
271         }
272         p = p->next;
273     }
274     apfw_trace("ico_apf_com_init_client: Leave(OK,fd=%d)", handle->fd);
275     return handle;
276 }
277
278 /*--------------------------------------------------------------------------*/
279 /**
280  * @brief   ico_apf_com_init_server
281  *          This function connects to aplicationto in AppsController.
282  *
283  * @param[in]   uri                 my URI, NULL is host myself
284  * @param[in]   type                connection type
285  * @return      handle address
286  * @retval      handle address      success
287  * @retval      NULL                error(failed connect AppsController)
288  */
289 /*--------------------------------------------------------------------------*/
290 ico_apf_com_handle_t *
291 ico_apf_com_init_server(const char *uri, const int type)
292 {
293     int i;
294     int port;
295     int svrtype;
296     char* address;
297     ico_apf_com_handle_t *handle;
298     Ico_Uxf_Sys_Config *sysconf;
299     Ico_Uxf_Sys_Config *ifsysconf = (Ico_Uxf_Sys_Config *)0xffffffff;
300     char *port_env;
301
302     apfw_trace("ico_apf_com_init_server: Enter(%s,%d)",
303                uri ? uri : "(NULL)", type);
304
305     ifsysconf = (Ico_Uxf_Sys_Config *)ico_uxf_ifGetSysConfig();
306
307     if (ifsysconf)  {
308         /* Another module already reads config file                             */
309         /* In this case, you don't release sysconf at finished this function.   */
310         sysconf = (Ico_Uxf_Sys_Config *)ifsysconf;
311     }
312     else    {
313         /* never read a system config                   */
314         sysconf = (Ico_Uxf_Sys_Config *)ico_uxf_getSysConfig();
315     }
316     if (!sysconf)   {
317         apfw_error("ico_apf_com_init_server: Leave(can not read configuration files)");
318         return NULL;
319     }
320
321     /* currently server support only Application Controler  */
322     svrtype = ICO_APF_COM_TYPE_SVR_APPSCTL;
323
324     /* If URI is host name, find address from config.   */
325     /* If node is a null character string, it regards NULL. */
326     Ico_Uxf_conf_host *phost =
327         (Ico_Uxf_conf_host *) ico_uxf_getSysHostById(ico_uxf_getSysHostByName(uri));
328     if (phost)  {
329         address = phost->address;
330     }
331     else    {
332         /* If don't find host name from config, regards ipaddress is set as node.*/
333         address = (char *)uri;
334     }
335
336     /* get a port number from system configuration(system/system.conf)  */
337     port = sysconf->misc.appscontrollerport;
338     apfw_trace("ico_apf_com_init_server: Config, Host=%s Port=%d", address, port);
339
340     /* environment variable for port        */
341     port = sysconf->misc.appscontrollerport;
342     port_env = getenv("ICO_APF_APPSCTL_PORT");
343     if (port_env) {
344         i = atoi(port_env);
345         if (i > 0)  port = i;
346     }
347
348     handle = handles;
349     while (handle)  {
350         if ((strcmp(address, handle->ip) == 0) &&
351             (handle->port == port) && (handle->type == svrtype))    break;
352         handle = handle->next;
353     }
354
355     if (handle) {
356         apfw_trace("ico_apf_com_init_server: Leave(Created)");
357         return handle;
358     }
359
360     handle = ico_apf_alloc_handle();
361     if (! handle)   {
362         apfw_error("ico_apf_com_init_server: Leave(No Memory)");
363         return NULL;
364     }
365
366     handle->type = svrtype;
367     handle->port = port;
368     strncpy(handle->ip, address, ICO_APF_RESOURCE_IP_LEN-1);
369     handle->ip[ICO_APF_RESOURCE_IP_LEN-1] = 0;
370
371     /* connect to AppsController            */
372     handle->wsi_context = libwebsocket_create_context(port, NULL, apps_protocols,
373                                                       libwebsocket_internal_extensions,
374                                                       NULL, NULL, -1, -1, 0);
375     if (! handle->wsi_context)  {
376         apfw_error("ico_apf_com_init_server: Leave(libwebsockets create Error)");
377         (void) ico_apf_com_term_server(handle);
378         return NULL;
379     }
380     apfw_trace("ico_apf_com_init_server: create server context 0x%08x",
381                (int)handle->wsi_context);
382
383     global_lwscontext = handle->wsi_context;
384
385     ico_apf_com_dispatch(handle, 0);
386
387     apfw_trace("ico_apf_com_init_server: Leave(OK)");
388     return handle;
389 }
390
391 /*--------------------------------------------------------------------------*/
392 /**
393  * @brief   ico_apf_alloc_handle
394  *          Allocate ccommunication handle.
395  *
396  * @param       none
397  * @return      handle address
398  * @retval      addres      success, return handle address
399  * @retval      NULL        error(no memory)
400  */
401 /*--------------------------------------------------------------------------*/
402 static ico_apf_com_handle_t *
403 ico_apf_alloc_handle(void)
404 {
405     ico_apf_com_handle_t *handle;
406     int     i;
407
408     if (! freehandles)  {
409
410         handle = malloc(sizeof(ico_apf_com_handle_t));
411         if (! handle)   {
412             return NULL;
413         }
414         memset(handle, 0, sizeof(ico_apf_com_handle_t));
415
416         /* Queue buffers initialize.                */
417         for (i = 0; i < ICO_APF_RESOURCE_WSOCK_BUFR; i++)   {
418             handle->rbuf[i] = calloc(sizeof(ico_apf_com_buffer_t), 1);
419             if (! handle->rbuf[i])  {
420                 return NULL;
421             }
422         }
423         for (i = 0; i < ICO_APF_RESOURCE_WSOCK_BUFS; i++)   {
424             handle->sbuf[i] = calloc(sizeof(ico_apf_com_buffer_t), 1);
425             if (! handle->sbuf[i])  {
426                 return NULL;
427             }
428         }
429     }
430     else    {
431         handle = freehandles;
432         freehandles = freehandles->next;
433         handle->next = NULL;
434         handle->fd = 0;
435         handle->pid = 0;
436         handle->wsi_context = NULL;
437         handle->wsi_connection = NULL;
438         handle->service_on = 0;
439         handle->retry = 0;
440         handle->stoprecv = 0;
441         handle->shead = 0;
442         handle->stail = 0;
443         handle->rhead = 0;
444         handle->rtail = 0;
445         handle->listener = NULL;
446         handle->user_data = NULL;
447         handle->type = 0;
448     }
449
450     if (handles)    {
451         handle->next = handles;
452     }
453     handles = handle;
454
455     return handle;
456 }
457
458 /*--------------------------------------------------------------------------*/
459 /**
460  * @brief   ico_apf_com_connect
461  *          This function connects to AppsController.
462  *
463  * @param[in]   handle          Communication handle
464  * @return      result status
465  * @retval      ICO_APF_RESOURCE_E_NONE             success
466  * @retval      ICO_APF_RESOURCE_E_INIT_COM_FAILD   error(connect failed)
467  */
468 /*--------------------------------------------------------------------------*/
469 static int
470 ico_apf_com_connect(ico_apf_com_handle_t *handle)
471 {
472     int     rep;
473
474     apfw_trace("ico_apf_com_connect: Enter(type=%d)", handle->type);
475
476     int ietf_version = -1;      /* latest */
477     char origin[1024];
478     sprintf(origin,"%d %s",getpid(),program_invocation_name);
479
480     apfw_trace("ico_apf_com_connect: libwebsocket_create_context");
481     handle->wsi_context = libwebsocket_create_context(
482                                     CONTEXT_PORT_NO_LISTEN, NULL,
483                                     (handle->type & ICO_APF_COM_TYPE_CONNECTION)
484                                             == ICO_APF_COM_TYPE_SOUNDMGR ?
485                                         sound_protocols : apps_protocols,
486                                     libwebsocket_internal_extensions,
487                                     NULL, NULL, -1, -1, 0);
488     if (handle->wsi_context == NULL) {
489         apfw_error("ico_apf_com_connect: Leave(RESOURCE_E_INIT_COM_FAILD)");
490         return ICO_APF_RESOURCE_E_INIT_COM_FAILD;
491     }
492     apfw_trace("ico_apf_com_connect: create client context 0x%08x",
493                (int)handle->wsi_context);
494
495     /* connect to Application Manager by WebSocket      */
496     apfw_trace("ico_apf_com_connect: libwebsocket_client_connect %s:%d",
497                handle->ip, handle->port);
498     for (rep = 0; rep < (1000/50); rep++)   {
499         handle->wsi_connection = libwebsocket_client_connect(
500                                         handle->wsi_context,
501                                         handle->ip, handle->port, 0,
502                                         "/", handle->ip, origin,
503                                         (handle->type == ICO_APF_COM_TYPE_APPSCTL) ?
504                                         apps_protocols[PROTOCOL_APPSCONTROLLER].name :
505                                         sound_protocols[PROTOCOL_SOUNDMGR].name,
506                                         ietf_version);
507         if (handle->wsi_connection) break;
508         usleep(50*1000);
509     }
510     if (handle->wsi_connection == NULL) {
511         apfw_warn("ico_apf_com_connect: Leave(RESOURCE_E_INIT_COM_FAILD)");
512         return ICO_APF_RESOURCE_E_INIT_COM_FAILD;
513     }
514     handle->fd = libwebsocket_get_socket_fd(handle->wsi_connection);
515     if (handle->fd > 0) {
516         (void)ico_apf_poll_fd_add(handle->fd, POLLIN|POLLOUT);
517     }
518     ico_apf_com_dispatch(handle, 0);
519
520     apfw_trace("ico_apf_com_connect: Leave(OK, fd=%d)", handle->fd);
521     return ICO_APF_RESOURCE_E_NONE;
522 }
523
524 /*--------------------------------------------------------------------------*/
525 /**
526  * @brief   ico_apf_com_isconnected
527  *          return a connection status with AppsController
528  *
529  * @param[in]   handle      AppsController's handle
530  * @return      connection status
531  * @retval      1           connect
532  * @retval      0           not connetc
533  */
534 /*--------------------------------------------------------------------------*/
535 int
536 ico_apf_com_isconnected(ico_apf_com_handle_t *handle)
537 {
538     return((handle != NULL) && (handle->service_on != 0));
539 }
540
541 /*--------------------------------------------------------------------------*/
542 /**
543  * @brief   ico_apf_com_dispatch
544  *          The accumulated transmitted and received data is processed.
545  *          Connecting AppsController program must call this function.
546  *
547  * @param[in]   handle      connect handle, if NULL target is all connect
548  * @param[in]   timeoutms   maximum wait time on miri-sec.
549  *                          0 is no wait, -1 is wait forever.
550  * @return      non
551  */
552 /*--------------------------------------------------------------------------*/
553 void
554 ico_apf_com_dispatch(ico_apf_com_handle_t *handle, const int timeoutms)
555 {
556     int rh;
557     int n;
558     ico_apf_com_handle_t *p;
559
560     if (! handles)  {
561         /* If program has not connected, nothing is done.   */
562         apfw_warn("ico_apf_com_dispatch: handle dose not exist");
563         return;
564     }
565
566     if (handle) {
567         p = handle;
568     }
569     else    {
570         p = handles;
571     }
572
573     while (p)   {
574         if (libwebsocket_service(p->wsi_context, timeoutms) < 0)    {
575             apfw_warn("ico_apf_com_dispatch: fd=%d is done", p->fd);
576         }
577
578         /* If received data is suspended, it processes.     */
579         while (p->rtail != p->rhead)    {
580             rh = p->rhead;
581             if (p->rhead >= (ICO_APF_RESOURCE_WSOCK_BUFR-1))    {
582                 p->rhead = 0;
583             }
584             else    {
585                 p->rhead ++;
586             }
587             n = p->rtail - p->rhead;
588             if (n < 0) {
589                 n = ICO_APF_RESOURCE_WSOCK_BUFR + n;
590             }
591             if ((p->stoprecv != 0) &&
592                 (n < (ICO_APF_RESOURCE_WSOCK_BUFR/2)))  {
593                 /* If suspending received data is bellow half, request a send process */
594                 p->stoprecv = 0;
595                 apfw_trace("ico_apf_com_dispatch: Flow Control(Start) %d", n);
596                 libwebsocket_rx_flow_control(p->wsi_connection, 1);
597                 libwebsocket_service(p->wsi_context, 0);
598             }
599
600             if (p->listener != NULL) {
601                 handle->listener(p, p->rbuf[rh]->cmd, p->rbuf[rh]->res, p->rbuf[rh]->pid,
602                                  p->rbuf[rh]->appid, p->rbuf[rh]->msg, p->user_data);
603                 libwebsocket_service(p->wsi_context, 0);
604             }
605             else if (global_listener != NULL) {
606                 global_listener(p, p->rbuf[rh]->cmd, p->rbuf[rh]->res, p->rbuf[rh]->pid,
607                                 p->rbuf[rh]->appid, p->rbuf[rh]->msg, global_user_data);
608                 libwebsocket_service(p->wsi_context, 0);
609             }
610         }
611         if (handle) break;
612         p = p->next;
613     }
614 }
615
616 /*--------------------------------------------------------------------------*/
617 /**
618  * @brief   ico_apf_com_term_client
619  *          finish to connect to AppsController
620  *          It recommends call this function before end of program
621  *          that used AppsController.
622  *
623  * @param[in]   handle      AppsController's handle
624  * @return      result
625  * @retval      ICO_APF_RESOURCE_E_NONE             success
626  * @retval      ICO_APF_RESOURCE_E_NOT_INITIALIZED  error(already finished)
627  */
628 /*--------------------------------------------------------------------------*/
629 int
630 ico_apf_com_term_client(ico_apf_com_handle_t *handle)
631 {
632     ico_apf_com_handle_t    *p;
633
634     apfw_trace("ico_apf_com_term_client: Enter");
635
636     if ((handle == NULL) || (handles == NULL))  {
637         apfw_trace("ico_apf_com_term_client: Leave(RESOURCE_E_NOT_INITIALIZED)");
638         return ICO_APF_RESOURCE_E_NOT_INITIALIZED;
639     }
640     handle->service_on = 0;
641
642     if (handle == handles)  {
643         handles = handles->next;
644     }
645     else    {
646         p = handles;
647         while (p)   {
648             if (p->next == handle)  break;
649             p = p->next;
650         }
651         if (! p)    {
652             apfw_trace("ico_apf_com_term_client: Leave(RESOURCE_E_NOT_INITIALIZED)");
653             return ICO_APF_RESOURCE_E_NOT_INITIALIZED;
654         }
655         p->next = handle->next;
656     }
657
658     if (handle->wsi_context)    {
659         libwebsocket_context_destroy(handle->wsi_context);
660     }
661     handle->next = freehandles;
662     freehandles = handle;
663
664     apfw_trace("ico_apf_com_term_client: Leave(OK)");
665     return ICO_APF_RESOURCE_E_NONE;
666 }
667
668 /*--------------------------------------------------------------------------*/
669 /**
670  * @brief   ico_apf_com_term_server
671  *          finish to connect to application
672  *
673  * @param[in]   handle      AppsController's handle
674  * @return      result
675  * @retval      ICO_APF_RESOURCE_E_NONE             success
676  * @retval      ICO_APF_RESOURCE_E_NOT_INITIALIZED  error(already finished)
677  */
678 /*--------------------------------------------------------------------------*/
679 int
680 ico_apf_com_term_server(ico_apf_com_handle_t *handle)
681 {
682     ico_apf_com_handle_t    *p;
683
684     apfw_trace("ico_apf_com_term_server: Enter");
685
686     if ((handle == NULL) || (handles == NULL))  {
687         apfw_trace("ico_apf_com_term_server: Leave(RESOURCE_E_NOT_INITIALIZED)");
688         return ICO_APF_RESOURCE_E_NOT_INITIALIZED;
689     }
690     handle->service_on = 0;
691
692     if (handle == handles)  {
693         handles = handles->next;
694     }
695     else    {
696         p = handles;
697         while (p)   {
698             if (p->next == handle)  break;
699             p = p->next;
700         }
701         if (! p)    {
702             apfw_trace("ico_apf_com_term_server: Leave(RESOURCE_E_NOT_INITIALIZED)");
703             return ICO_APF_RESOURCE_E_NOT_INITIALIZED;
704         }
705         p->next = handle->next;
706     }
707
708     if (handle->wsi_context)    {
709         libwebsocket_context_destroy(handle->wsi_context);
710     }
711     handle->next = freehandles;
712     freehandles = handle;
713
714     apfw_trace("ico_apf_com_term_server: Leave(OK)");
715     return ICO_APF_RESOURCE_E_NONE;
716 }
717
718 /*--------------------------------------------------------------------------*/
719 /**
720  * @brief   ico_apf_com_send
721  *          Accumulates the data send to AppsController/application.
722  *
723  * @param[in]   handle      AppsController's handle
724  * @param[in]   cmd         command
725  * @param[in]   res         resource
726  * @param[in]   appid       application id
727  * @param[in]   msg         send message
728  * @return      result
729  * @retval      ICO_APF_RESOURCE_E_NONE             success
730  * @retval      ICO_APF_RESOURCE_E_NOT_INITIALIZED  error(not connect)
731  * @retval      ICO_APF_RESOURCE_E_COMMUNICATION    error(cannot send)
732  * @retval      ICO_APF_RESOURCE_E_INVAL            error(invalid parameter)
733  */
734 /*--------------------------------------------------------------------------*/
735 int
736 ico_apf_com_send(ico_apf_com_handle_t *handle,
737                  const int cmd, const int res, const char *appid, char *msg)
738 {
739     int     st;
740     int     len;
741
742     apfw_trace("ico_apf_com_send: Enter(%08x, %d, %d)", (int)handle, cmd, res);
743
744     if ((handle == NULL) || (! ico_apf_com_isconnected(handle)))    {
745         apfw_warn("ico_apf_com_send: Leave(not initialized)");
746         return ICO_APF_RESOURCE_E_NOT_INITIALIZED;
747     }
748     if ((handle->type & ICO_APF_COM_TYPE_CONNECTION) != ICO_APF_COM_TYPE_SOUNDMGR)  {
749         /* send to AppsController               */
750         if ((cmd < ICO_APF_RESOURCE_COMMAND_MIN) ||
751             (cmd > ICO_APF_RESOURCE_COMMAND_MAX) ||
752             (res < ICO_APF_RESOURCE_RESID_MIN) ||
753             (res > ICO_APF_RESOURCE_RESID_MAX))   {
754             apfw_warn("ico_apf_com_send: Leave(invalid command for resource)");
755             return ICO_APF_RESOURCE_E_INVAL;
756         }
757     }
758     else    {
759         /* send to Multi Sound Manager          */
760         if ((cmd < ICO_APF_SOUND_COMMAND_MIN) ||
761             (cmd > ICO_APF_SOUND_COMMAND_CMD))  {
762             apfw_warn("ico_apf_com_send: Leave(invalid command for sound control)");
763             return ICO_APF_RESOURCE_E_INVAL;
764         }
765     }
766
767     if (msg)    {
768         len = strlen(msg);
769         if (len >= ICO_APF_RESOURCE_MSG_LEN)    {
770             apfw_warn("ico_apf_com_send: Leave(invalid message length)");
771             return ICO_APF_RESOURCE_E_INVAL;
772         }
773     }
774     else    {
775         len = 0;
776         msg = "(NULL)";
777     }
778
779     st = handle->stail;
780
781     if (st >= (ICO_APF_RESOURCE_WSOCK_BUFS-1))  {
782         st = 0;
783     }
784     else    {
785         st ++;
786     }
787     if (st == handle->shead)    {
788         /* send buffer is full                  */
789         ico_apf_poll_write_event(handle, 3);
790
791         apfw_error("ico_apf_com_send: Leave(send buffer overflow)");
792         ico_apf_poll_fd_del(handle->fd);
793         return ICO_APF_RESOURCE_E_COMMUNICATION;
794     }
795
796     /* accumulate send buffer                   */
797     if ((! appid) || (*appid == 0)) {
798         handle->sbuf[handle->stail]->pid = getpid();
799         handle->sbuf[handle->stail]->appid[0] = 0;
800     }
801     else    {
802         handle->sbuf[handle->stail]->pid = 0;
803         strncpy(handle->sbuf[handle->stail]->appid, appid, ICO_UXF_MAX_PROCESS_NAME);
804         handle->sbuf[handle->stail]->appid[ICO_UXF_MAX_PROCESS_NAME] = 0;
805     }
806     apfw_trace("ico_apf_com_send: Send.%d:%d %d %d(%s) <%s>",
807                handle->stail, cmd, res, handle->sbuf[handle->stail]->pid,
808                handle->sbuf[handle->stail]->appid, msg);
809     handle->sbuf[handle->stail]->cmd = cmd;
810     handle->sbuf[handle->stail]->res = res;
811     memcpy(handle->sbuf[handle->stail]->msg, msg, len);
812     handle->sbuf[handle->stail]->msg[len] = 0;
813     handle->stail = st;
814
815     libwebsocket_callback_on_writable(handle->wsi_context, handle->wsi_connection);
816
817     if (lws_callbacked) {
818         /* send call from libwensockets callback, delayed send  */
819         ico_apf_poll_write_event(handle, 1);
820     }
821     else    {
822         /* not call from callback, direct send                  */
823         ico_apf_com_dispatch(handle, 0);        /* try to service           */
824     }
825     apfw_trace("ico_apf_com_send: Leave(OK)");
826     return ICO_APF_RESOURCE_E_NONE;
827 }
828
829 /*--------------------------------------------------------------------------*/
830 /**
831  * @brief   ico_apf_com_realsend
832  *          send messege to AppsController
833  *
834  * @param[in]   handle      AppsController's handle
835  * @param[in]   msg         Send message
836  * @return      result
837  * @retval      ICO_APF_RESOURCE_E_NONE             success
838  * @retval      ICO_APF_RESOURCE_E_NOT_INITIALIZED  error(not connect)
839  * @retval      ICO_APF_RESOURCE_E_COMMUNICATION    error(cannot send)
840  * @retval      ICO_APF_RESOURCE_E_INVAL            error(invalid parameter)
841  */
842 /*--------------------------------------------------------------------------*/
843 static int
844 ico_apf_com_realsend(ico_apf_com_handle_t *handle, ico_apf_com_buffer_t *msg)
845 {
846     unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 +
847                           LWS_SEND_BUFFER_POST_PADDING];
848     unsigned char *pt = &buf[LWS_SEND_BUFFER_PRE_PADDING];
849     int     n;
850
851     apfw_trace("ico_apf_com_realsend: Enter");
852     if ((handle == NULL) || (! ico_apf_com_isconnected(handle)))    {
853         apfw_warn("ico_apf_com_realsend: Leave(Not initialized)");
854         return ICO_APF_RESOURCE_E_NOT_INITIALIZED;
855     }
856
857     if ((handle->type & ICO_APF_COM_TYPE_CONNECTION) == ICO_APF_COM_TYPE_SOUNDMGR)  {
858         /* send to Multi Sound Manager          */
859         if (msg->res)   {
860             sprintf((char *)pt, "%s %d",
861                     ico_apf_sound_table[msg->cmd-ICO_APF_SOUND_COMMAND_MIN], msg->res);
862         }
863         else    {
864             strcpy((char *)pt, ico_apf_sound_table[msg->cmd-ICO_APF_SOUND_COMMAND_MIN]);
865         }
866     }
867     else    {
868         /* send tp AppsController               */
869         if (msg->appid[0])  {
870             sprintf((char *)pt, "%s %s %s %s",
871                     ico_apf_cmd_table[msg->cmd-ICO_APF_RESOURCE_COMMAND_MIN],
872                     ico_apf_res_table[msg->res-ICO_APF_RESOURCE_RESID_MIN],
873                     msg->appid, msg->msg);
874         }
875         else    {
876             sprintf((char *)pt, "%s %s %d %s",
877                     ico_apf_cmd_table[msg->cmd-ICO_APF_RESOURCE_COMMAND_MIN],
878                     ico_apf_res_table[msg->res-ICO_APF_RESOURCE_RESID_MIN],
879                     msg->pid, msg->msg);
880         }
881     }
882
883     apfw_trace("ico_apf_com_realsend: libwebsocket_write[%s]", pt);
884     n = libwebsocket_write(handle->wsi_connection,
885                            pt, strlen((char *)pt), LWS_WRITE_TEXT);
886     if (n < 0)  {
887         apfw_error("ico_apf_com_realsend: write error[%d]", n);
888         ico_apf_poll_fd_del(handle->fd);
889         return ICO_APF_RESOURCE_E_COMMUNICATION;
890     }
891     usleep(200);    /* According to libwebsockets's sample, this is required    */
892     apfw_trace("ico_apf_com_realsend: Leave(OK)");
893     return ICO_APF_RESOURCE_E_NONE;
894 }
895
896 /*--------------------------------------------------------------------------*/
897 /**
898  * @brief   ico_apf_com_addeventlistener
899  *          register a callback function called receive message from AppsController
900  *
901  * @param[in]   handle      AppsComtroller's handle
902  * @param[in]   listener    callback function
903  * @param[in]   user_data   Arbitrary data
904  * @return      result
905  * @retval      ICO_APF_RESOURCE_E_NONE             success
906  * @retval      ICO_APF_RESOURCE_E_NOT_INITIALIZED  error(not connect)
907  * @retval      ICO_APF_RESOURCE_E_INVAL            error(already registed)
908  */
909 /*--------------------------------------------------------------------------*/
910 int
911 ico_apf_com_addeventlistener(ico_apf_com_handle_t *handle,
912                              ico_apf_com_eventlistener listener, void* user_data)
913 {
914     if (handle == NULL) {
915         if (global_listener)    {
916             return ICO_APF_RESOURCE_E_INVAL;
917         }
918         global_listener = listener;
919         global_user_data = user_data;
920         return ICO_APF_RESOURCE_E_NONE;
921     }
922
923     if (handle->listener)   {
924         return ICO_APF_RESOURCE_E_INVAL;
925     }
926     handle->user_data = user_data;
927     handle->listener = listener;
928
929     if (! global_listener)  {
930         /* save listener        */
931         global_listener = listener;
932     }
933     return ICO_APF_RESOURCE_E_NONE;
934 }
935
936 /*--------------------------------------------------------------------------*/
937 /**
938  * @brief   ico_apf_com_removeeventlistener
939  *          unregister a callback function called receive message
940  *
941  * @param[in]   handle      AppsComtroller's handle
942  * @return      result
943  * @retval      ICO_APF_RESOURCE_E_NONE             success
944  * @retval      ICO_APF_RESOURCE_E_NOT_INITIALIZED  error(not connect)
945  * @retval      ICO_APF_RESOURCE_E_INVAL            error(do not registed)
946  */
947 /*--------------------------------------------------------------------------*/
948 int
949 ico_apf_com_removeeventlistener(ico_apf_com_handle_t *handle)
950 {
951     if (handle == NULL) {
952         if (! global_listener)  {
953             return ICO_APF_RESOURCE_E_INVAL;
954         }
955         global_listener = NULL;
956         global_user_data = NULL;
957         return ICO_APF_RESOURCE_E_NONE;
958     }
959
960     if (! handle->listener) {
961         return ICO_APF_RESOURCE_E_INVAL;
962     }
963     handle->listener = NULL;
964     handle->user_data = NULL;
965
966     return ICO_APF_RESOURCE_E_NONE;
967 }
968
969 /*--------------------------------------------------------------------------*/
970 /**
971  * @brief   ico_apf_callback_http
972  *          Connection status is notified from libwebsockets.
973  *
974  * @param[in]   context     libwebsockets context
975  * @param[in]   wsi         libwebsockets management table
976  * @param[in]   reason      event type
977  * @param[in]   user        intact
978  * @param[in]   in          receive message
979  * @param[in]   len         message size[BYTE]
980  * @return      result
981  * @retval      =0          success
982  * @retval      =1          error
983  */
984 /*--------------------------------------------------------------------------*/
985 static int
986 ico_apf_callback_http(struct libwebsocket_context *context,
987                       struct libwebsocket *wsi,
988                       enum libwebsocket_callback_reasons reason,
989                       void *user, void *in, size_t len)
990 {
991     int fd;
992
993     fd = libwebsocket_get_socket_fd(wsi);
994     lws_callbacked ++;
995
996     switch (reason) {
997     case LWS_CALLBACK_FILTER_NETWORK_CONNECTION:
998                                             /* a connection demand is received  */
999         apfw_trace("ico_apf_callback_http: LWS_CALLBACK_FILTER_NETWORK_CONNECTION fd=%d", fd);
1000
1001         /* If connection is refused, it will return with values other than zero.*/
1002         /* At present, since access control is not introduced,                  */
1003         /* connection is always permitted.                                      */
1004         break;
1005
1006     case LWS_CALLBACK_ADD_POLL_FD:          /* add connection socket            */
1007         apfw_trace("ico_apf_callback_http: LWS_CALLBACK_ADD_POLL_FD(%d) %d,%x", fd,
1008                    (int)user, len);
1009         (void)ico_apf_poll_fd_add((int)user, (int)len);
1010         break;
1011
1012     case LWS_CALLBACK_DEL_POLL_FD:          /* delete connection socket         */
1013         apfw_trace("ico_apf_callback_http: LWS_CALLBACK_DEL_POLL_FD(%d) %d,%x", fd,
1014                    (int)user, len);
1015         ico_apf_poll_fd_del((int)user);
1016         break;
1017
1018     case LWS_CALLBACK_SET_MODE_POLL_FD:     /* set status                       */
1019         apfw_trace("ico_apf_callback_http: LWS_CALLBACK_SET_MODE_POLL_FD(%d) %d,%x", fd,
1020                    (int)user, len);
1021         (void)ico_apf_poll_fd_add((int)user, (int)len);
1022         break;
1023
1024     case LWS_CALLBACK_CLEAR_MODE_POLL_FD:   /* clear status                     */
1025         apfw_trace("ico_apf_callback_http: LWS_CALLBACK_CLEAR_MODE_POLL_FD(%d) %d,%x", fd,
1026                    (int)user, len);
1027         (void)ico_apf_poll_fd_add((int)user, -((int)len));
1028         break;
1029
1030     default:
1031         apfw_trace("ico_apf_callback_http: Unknown reason(%d, fd=%d)", reason, fd);
1032         break;
1033     }
1034     lws_callbacked --;
1035
1036     return 0;
1037 }
1038
1039 /*--------------------------------------------------------------------------*/
1040 /**
1041  * @brief   ico_apf_callback_websock
1042  *          this callback function notified from libwebsockets.
1043  *
1044  * @param[in]   context     libwebsockets context
1045  * @param[in]   wsi         libwebsockets management table
1046  * @param[in]   reason      event type
1047  * @param[in]   user        intact
1048  * @param[in]   in          receive message
1049  * @param[in]   len         message size[BYTE]
1050  * @return      result
1051  * @retval      =0          success
1052  * @retval      =1          error
1053  */
1054 /*--------------------------------------------------------------------------*/
1055 static int
1056 ico_apf_callback_websock(struct libwebsocket_context * this,
1057                          struct libwebsocket *wsi,
1058                          enum libwebsocket_callback_reasons reason,
1059                          void *user, void *in, size_t len)
1060 {
1061     int     wsifd;
1062     int     st;
1063     int     cmd;
1064     int     res;
1065     int     pid;
1066     int     i;
1067     int     strlen;
1068     char    *msg;
1069     ico_apf_com_poll_t *p;
1070     ico_apf_com_handle_t *handle;
1071     struct sockaddr_in  sin;
1072     unsigned int        sin_len;
1073     char    appid[ICO_UXF_MAX_PROCESS_NAME+1];
1074     char    strname[ICO_UXF_MAX_STREAM_NAME+1];
1075     int     nparam;
1076     struct  {
1077         short   start;
1078         short   end;
1079     }       param[10];
1080
1081     wsifd = libwebsocket_get_socket_fd(wsi);
1082
1083     lws_callbacked ++;
1084
1085     if (reason == LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION)  {
1086         apfw_trace("ico_apf_callback_websock: server side connected from client");
1087
1088         /* connect from client      */
1089         handle = handles;
1090         while (handle)  {
1091             if (handle->fd == wsifd)    break;
1092             handle = handle->next;
1093         }
1094         if (! handle)   {
1095             handle = ico_apf_alloc_handle();
1096             if (! handle)   {
1097                 lws_callbacked --;
1098                 apfw_error("ico_apf_callback_websock: No Memory");
1099                 return 1;
1100             }
1101         }
1102         handle->type = ICO_APF_COM_TYPE_APPSCTL;
1103         handle->wsi_context = global_lwscontext;
1104         handle->wsi_connection = wsi;
1105         handle->fd = wsifd;
1106         handle->service_on = 0;
1107         handle->stoprecv = 0;
1108
1109         sin_len = sizeof(sin);
1110         if (getpeername(wsifd, (struct sockaddr *) &sin, &sin_len) >= 0)  {
1111             sprintf(handle->ip, "%u.%u.%u.%u",
1112                     (sin.sin_addr.s_addr) & 0x0ff,
1113                     (sin.sin_addr.s_addr >> 8) & 0x0ff,
1114                     (sin.sin_addr.s_addr >> 16) & 0x0ff,
1115                     (sin.sin_addr.s_addr >> 24) & 0x0ff);
1116         }
1117         else    {
1118             strcpy(handle->ip, "127.0.0.1");
1119         }
1120
1121         p = com_polls;
1122         while (p)   {
1123             if (p->fd == handle->fd)    {
1124                 p->apf_fd_control = (void *)handle;
1125                 handle->poll = p;
1126             }
1127             p = p->next;
1128         }
1129         lws_callbacked --;
1130         apfw_trace("ico_apf_callback_websock: server side connected");
1131         return 0;
1132     }
1133
1134     handle = handles;
1135     while (handle)  {
1136         if (handle->wsi_connection == wsi) break;
1137         handle = handle->next;
1138     }
1139
1140     if (! handle)   {
1141         lws_callbacked --;
1142         apfw_trace("ico_apf_callback_websock: Handle not exist");
1143         return 0;
1144     }
1145
1146     switch (reason) {
1147     case LWS_CALLBACK_CLIENT_ESTABLISHED:
1148     case LWS_CALLBACK_ESTABLISHED:
1149         apfw_trace("ico_apf_callback_websock: LWS_CALLBACK_ESTABLISHED");
1150         handle->service_on = 1;
1151         handle->stoprecv = 0;
1152
1153         /* save receive message to receive buffer       */
1154         ico_apf_put_recvmsg(ICO_APF_RESOURCE_STATE_CONNECTED, 0,
1155                             handle->pid, "\0", NULL, 0, handle);
1156         break;
1157
1158     case LWS_CALLBACK_ADD_POLL_FD:          /* add connection socket            */
1159         (void)ico_apf_poll_fd_add((int)user, (int)len);
1160         break;
1161
1162     case LWS_CALLBACK_DEL_POLL_FD:          /* delete connection socket         */
1163         ico_apf_poll_fd_del((int)user);
1164         break;
1165
1166     case LWS_CALLBACK_SET_MODE_POLL_FD:     /* set status                       */
1167         (void)ico_apf_poll_fd_add((int)user, (int)len);
1168         break;
1169
1170     case LWS_CALLBACK_CLEAR_MODE_POLL_FD:   /* clear status                     */
1171         (void)ico_apf_poll_fd_add((int)user, -((int)len));
1172         break;
1173
1174     case LWS_CALLBACK_CLOSED:
1175         apfw_trace("ico_apf_callback_websock: LWS_CALLBACK_CLOSED");
1176         handle->service_on = 0;
1177
1178         /* save receive message to receive buffer       */
1179         ico_apf_put_recvmsg(ICO_APF_RESOURCE_STATE_DISCONNECTED, 0,
1180                             handle->pid, "\0", NULL, 0, handle);
1181         break;
1182
1183     case LWS_CALLBACK_CLIENT_WRITEABLE:
1184     case LWS_CALLBACK_SERVER_WRITEABLE:
1185         if (handle->stail != handle->shead)    {
1186             st = handle->shead;
1187             if (handle->shead >= (ICO_APF_RESOURCE_WSOCK_BUFS-1))  {
1188                 handle->shead = 0;
1189             }
1190             else    {
1191                 handle->shead ++;
1192             }
1193             if (ico_apf_com_realsend(handle, handle->sbuf[st])
1194                         != ICO_APF_RESOURCE_E_NONE) {
1195                 apfw_warn("ico_apf_callback_websock: ico_apf_com_realsend Error");
1196                 handle->shead = st;
1197             }
1198             if (handle->stail != handle->shead)    {
1199                 libwebsocket_callback_on_writable(handle->wsi_context,
1200                                                   handle->wsi_connection);
1201             }
1202         }
1203         break;
1204
1205     case LWS_CALLBACK_CLIENT_RECEIVE:
1206     case LWS_CALLBACK_RECEIVE:
1207         msg = (char *)in;
1208         msg[len] = 0;
1209         if ((len <= 9) || (len >= (ICO_APF_RESOURCE_MSG_LEN+9)))    {
1210             lws_callbacked --;
1211             apfw_warn("ico_apf_callback_websock: Receive Length Error, Len=%d", len);
1212             return 0;
1213         }
1214         apfw_trace("ico_apf_callback_websock: LWS_CALLBACK_RECEIVE[%s]", msg);
1215
1216         /* analize event code               */
1217         if ((handle->type & ICO_APF_COM_TYPE_CONNECTION)
1218                 == ICO_APF_COM_TYPE_SOUNDMGR)   {
1219             /* Multi Sound Manager          */
1220             i = 0;
1221             for (nparam = 0; nparam < 10; nparam++) {
1222                 for (; msg[i]; i++) {
1223                     if (msg[i] != ' ')  break;
1224                 }
1225                 if (msg[i] == 0)    break;
1226                 param[nparam].start = i;
1227                 for (; msg[i]; i++) {
1228                     if (msg[i] == ' ')  break;
1229                 }
1230                 param[nparam].end = i;
1231             }
1232             if (nparam <= 0)    {
1233                 lws_callbacked --;
1234                 apfw_warn("ico_apf_callback_websock: Illegal Message Format(no param)");
1235                 return 0;
1236             }
1237             for (cmd = ICO_APF_SOUND_COMMAND_CMD+1;
1238                  cmd <= ICO_APF_SOUND_COMMAND_MAX; cmd++)    {
1239                 if (memcmp(&msg[param[0].start],
1240                            ico_apf_sound_table[cmd-ICO_APF_SOUND_COMMAND_MIN],
1241                            param[0].end - param[0].start) == 0) break;
1242             }
1243             if (cmd > ICO_APF_SOUND_COMMAND_MAX)    {
1244                 lws_callbacked --;
1245                 apfw_warn("ico_apf_callback_websock: Receive Event Error(cmd=%d)", cmd);
1246                 return 0;
1247             }
1248             res = ICO_APF_RESID_BASIC_SOUND;
1249             pid = 0;
1250             appid[0] = 0;
1251             strname[0] = 0;
1252             strlen = 0;
1253             for (i = 1; i < nparam; i++)    {
1254                 if (memcmp(&msg[param[i].start],
1255                            "#pid#", param[i].end - param[i].start) == 0)    {
1256                     i ++;
1257                     if (i < nparam) {
1258                         pid = strtol(&msg[param[i].start], (char **)0, 0);
1259                         if (ico_apf_get_app_id(pid, appid) != ICO_APP_CTL_E_NONE)   {
1260                             lws_callbacked --;
1261                             apfw_trace("ico_apf_callback_websock: Unknown pid=%d", pid);
1262                             return 0;
1263                         }
1264                     }
1265                 }
1266                 else if (memcmp(&msg[param[i].start],
1267                                 "#stream_name#", param[i].end - param[i].start) == 0) {
1268                     i ++;
1269                     /* no need stream name      */
1270                 }
1271                 else if (memcmp(&msg[param[i].start],
1272                                 "#app_name#", param[i].end - param[i].start) == 0) {
1273                     i ++;
1274                     if (i < nparam) {
1275                         strlen = param[i].end - param[i].start;
1276                         if (strlen >= ((int)sizeof(strname)))
1277                             strlen = sizeof(strname) - 1;
1278                         strncpy(strname, &msg[param[i].start], strlen);
1279                         strname[strlen] = 0;
1280                     }
1281                 }
1282                 else if (memcmp(&msg[param[i].start],
1283                                 "#stream_state#", param[i].end - param[i].start) == 0) {
1284                     i ++;
1285                     /* no need stream_state     */
1286                 }
1287             }
1288             apfw_trace("ico_apf_callback_websock: SoundMgr evt=%d res=%d(%s.%d) str=%s",
1289                        cmd, res, appid, pid, strname);
1290             /* save receive message to receive buffer       */
1291             ico_apf_put_recvmsg(cmd, res, pid, appid, strname, strlen, handle);
1292         }
1293         else    {
1294             /* AppsController               */
1295             for (cmd = ICO_APF_RESOURCE_COMMAND_MIN;
1296                  cmd <= ICO_APF_RESOURCE_COMMAND_MAX; cmd++)    {
1297                 if (memcmp(msg,
1298                            ico_apf_cmd_table[cmd-ICO_APF_RESOURCE_COMMAND_MIN], 3)
1299                         == 0)   break;
1300             }
1301             if (cmd > ICO_APF_RESOURCE_COMMAND_MAX) {
1302                 lws_callbacked --;
1303                 apfw_warn("ico_apf_callback_appsctl: Receive Event Error(cmd=%d)", cmd);
1304                 return 0;
1305             }
1306             for (res = ICO_APF_RESOURCE_RESID_MIN;
1307                  res <= ICO_APF_RESOURCE_RESID_MAX; res++)  {
1308                 if (memcmp(&msg[4],
1309                     ico_apf_res_table[res-ICO_APF_RESOURCE_RESID_MIN], 4) == 0) break;
1310             }
1311             if (res > ICO_APF_RESOURCE_RESID_MAX)   {
1312                 lws_callbacked --;
1313                 apfw_warn("ico_apf_callback_websock: Receive Resource Error(resid=%d)",
1314                           res);
1315                 return 0;
1316             }
1317
1318             pid = 0;
1319             for (st = 9; msg[st]; st++) {
1320                 if (msg[st] == ' ') break;
1321                 if (pid >= 0)   {
1322                     if ((msg[st] >= '0') && (msg[st] <= '9'))   {
1323                         pid = pid * 10 + msg[st] - '0';
1324                     }
1325                     else    {
1326                         pid = -1;
1327                     }
1328                 }
1329             }
1330             if (pid >= 0)   {
1331                 appid[0] = 0;
1332             }
1333             else    {
1334                 pid = st - 9;
1335                 if (pid > ICO_UXF_MAX_PROCESS_NAME )
1336                     pid = ICO_UXF_MAX_PROCESS_NAME;
1337                 strncpy(appid, &msg[9], pid);
1338                 appid[pid] = 0;
1339                 pid = 0;
1340             }
1341             if (msg[st] == ' ') st++;
1342             apfw_trace("ico_apf_callback_websock: AppsCtl evt=%d res=%d pid=%d(%s) msg=%s",
1343                        cmd, res, pid, appid, &msg[st]);
1344             /* save receive message to receive buffer       */
1345             ico_apf_put_recvmsg(cmd, res, pid, appid, &msg[st], len-st, handle);
1346         }
1347         break;
1348     default:
1349         apfw_trace("ico_apf_callback_websock: UnKnown reason=%d", reason);
1350         break;
1351     }
1352     lws_callbacked --;
1353
1354     return 0;
1355 }
1356
1357 /*--------------------------------------------------------------------------*/
1358 /**
1359  * @brief   ico_apf_put_recvmsg
1360  *          put receive message into receive buffer
1361  *
1362  * @param[in]   cmd         receive commnad or event
1363  * @param[in]   res         receive resource
1364  * @param[in]   pid         request pid
1365  * @param[in]   appid       application id (for Web Application)
1366  * @param[in]   msg         receive message
1367  * @param[in]   len         receive message length
1368  * @param[out]  handle      connection handle
1369  * @return      none
1370  */
1371 /*--------------------------------------------------------------------------*/
1372 static void
1373 ico_apf_put_recvmsg(const int cmd, const int res, const int pid, const char *appid,
1374                     char *msg, const int len, ico_apf_com_handle_t *handle)
1375 {
1376     int     i;
1377     int     nexttail;
1378
1379     /* check receive buffer overflow        */
1380     if (handle->rtail >= (ICO_APF_RESOURCE_WSOCK_BUFR-1))  {
1381         nexttail = 0;
1382     }
1383     else    {
1384         nexttail = handle->rtail + 1;
1385     }
1386     if (handle->rhead == nexttail)  {
1387         /* receive buffer overflow, drops all message   */
1388         apfw_warn("ico_apf_put_recvmsg: receive buffer overflow");
1389         handle->rhead = 0;
1390         handle->rtail = 0;
1391         nexttail = 1;
1392     }
1393
1394     /* receive message is put into queue.     */
1395     handle->rbuf[handle->rtail]->cmd = cmd;
1396     handle->rbuf[handle->rtail]->res = res;
1397     handle->rbuf[handle->rtail]->pid = pid;
1398     strncpy(handle->rbuf[handle->rtail]->appid, appid, ICO_UXF_MAX_PROCESS_NAME);
1399     handle->rbuf[handle->rtail]->appid[ICO_UXF_MAX_PROCESS_NAME] = 0;
1400     if (msg)    {
1401         memcpy(handle->rbuf[handle->rtail]->msg, msg, len);
1402         handle->rbuf[handle->rtail]->msg[len] = 0;
1403     }
1404     else    {
1405         handle->rbuf[handle->rtail]->msg[0] = 0;
1406     }
1407     handle->rtail = nexttail;
1408     i = handle->rtail - handle->rhead;
1409     if (i <= 0)    {
1410         i = ICO_APF_RESOURCE_WSOCK_BUFR + i;
1411     }
1412     if ((handle->stoprecv == 0) &&
1413         (i > ((ICO_APF_RESOURCE_WSOCK_BUFR * 3) / 4)))    {
1414         /* request to stop sending if an opening is less than 25%.   */
1415         handle->stoprecv = 1;
1416         apfw_trace("ico_apf_put_recvmsg: Flow Control(Stop) %d", i);
1417         libwebsocket_rx_flow_control(handle->wsi_connection, 0);
1418     }
1419     ico_apf_poll_write_event(handle, 1);
1420 }
1421
1422 /*--------------------------------------------------------------------------*/
1423 /**
1424  * @brief   apf_com_poll_fd_add: add file descriptor for poll
1425  *
1426  * @param[in]   fd          file descriptor
1427  * @param[in]   flag        POLL flag(POLLIN,POLLOUT)
1428  *                          negative means reset
1429  * @return      result
1430  * @retval      ICO_APF_RESOURCE_E_NONE             success
1431  * @retval      ICO_APF_RESOURCE_E_INVAL            error(out of memory)
1432  */
1433 /*--------------------------------------------------------------------------*/
1434 static int
1435 ico_apf_poll_fd_add(const int fd, const int flag)
1436 {
1437     ico_apf_com_poll_t      *p;
1438     ico_apf_com_poll_t      *fds[1];
1439     ico_apf_com_handle_t    *handle;
1440
1441     p = com_polls;
1442     while (p)   {
1443         if (p->fd == fd)    {
1444             break;
1445         }
1446         p = p->next;
1447     }
1448
1449     if (! p)    {
1450         /* new file descriptor              */
1451         if (freecom_polls)   {
1452             p = freecom_polls;
1453             freecom_polls = p->next;
1454             p->apf_fd_control = NULL;
1455             p->user_data = NULL;
1456         }
1457         else    {
1458             p = calloc(sizeof(ico_apf_com_poll_t), 1);
1459             if (! p)    {
1460                 /* out of memory            */
1461                 apfw_error("ico_apf_poll_fd_add: can not allocate fd control table"
1462                            "(No Memory)");
1463                 return ICO_APF_RESOURCE_E_INVAL;
1464             }
1465         }
1466
1467         p->fd = fd;
1468         p->next = com_polls;
1469         com_polls = p;
1470     }
1471     p->flags |= ICO_APF_COM_POLL_ERROR;
1472     if (flag >= 0)  {
1473         if (flag & (POLLIN|POLLPRI))    {
1474             p->flags |= ICO_APF_COM_POLL_READ;
1475         }
1476         if (flag & POLLOUT) {
1477             p->flags |= ICO_APF_COM_POLL_WRITE;
1478         }
1479     }
1480     else    {
1481         if ((-flag) & (POLLIN|POLLPRI)) {
1482             p->flags &= ~ICO_APF_COM_POLL_READ;
1483         }
1484         if ((-flag) & POLLOUT)  {
1485             p->flags &= ~ICO_APF_COM_POLL_WRITE;
1486         }
1487     }
1488
1489     handle = handles;
1490     while (handle)  {
1491         if (handle->fd == fd)   break;
1492         handle = handle->next;
1493     }
1494     if (handle) {
1495         p->apf_fd_control = (void *)handle;
1496         handle->poll = p;
1497     }
1498     else    {
1499         apfw_trace("ico_apf_poll_fd_add: fd=%d dose not exist in handles", fd);
1500         p->apf_fd_control = NULL;
1501     }
1502
1503     /* regist callback function */
1504     if (ico_apf_pollfd_func)    {
1505         fds[0] = p;
1506
1507         (*ico_apf_pollfd_func)(fds, 1);
1508     }
1509     return ICO_APF_RESOURCE_E_NONE;
1510 }
1511
1512 /*--------------------------------------------------------------------------*/
1513 /**
1514  * @brief   apf_com_poll_fd_del: delete file descriptor for poll
1515  *
1516  * @param[in]   fd          file descriptor
1517  * @return      none
1518  */
1519 /*--------------------------------------------------------------------------*/
1520 static void
1521 ico_apf_poll_fd_del(const int fd)
1522 {
1523     ico_apf_com_poll_t      *p;
1524     ico_apf_com_poll_t      *bp;
1525     ico_apf_com_poll_t      *fds[1];
1526
1527     /* search file descriptor       */
1528     p = com_polls;
1529     bp = NULL;
1530     while (p)   {
1531         if (p->fd == fd)    {
1532             if (bp) {
1533                 bp->next = p->next;
1534             }
1535             else    {
1536                 com_polls = p->next;
1537             }
1538
1539             if (p->apf_fd_control)  {
1540                 ((ico_apf_com_handle_t *)(p->apf_fd_control))->poll = NULL;
1541             }
1542
1543             /* call callback function       */
1544             if (ico_apf_pollfd_func)    {
1545                 p->flags = 0;
1546                 fds[0] = p;
1547
1548                 (*ico_apf_pollfd_func)(fds, 1);
1549             }
1550             p->next = freecom_polls;
1551             freecom_polls = p;
1552             break;
1553         }
1554         p = p->next;
1555     }
1556 }
1557
1558 /*--------------------------------------------------------------------------*/
1559 /**
1560  * @brief   ico_apf_com_poll_fd_control: Set or Unset callback of file descriptors
1561  *
1562  * @param[in]   poll_fd_cb      The callback function.
1563  * @return      result
1564  * @retval      ICO_APF_RESOURCE_E_NONE             success
1565  */
1566 /*--------------------------------------------------------------------------*/
1567 ICO_APF_API int
1568 ico_apf_com_poll_fd_control(ico_apf_com_pollfd_cb poll_fd_cb)
1569 {
1570     ico_apf_com_poll_t *p;
1571     ico_apf_com_poll_t **fds;
1572     int     nfds;
1573     int     count;
1574
1575     /* regist callback function     */
1576     ico_apf_pollfd_func = poll_fd_cb;
1577
1578     if (ico_apf_pollfd_func)    {
1579         /* if regist, call callback for all file descriptors    */
1580
1581         /* count number of file descriptors */
1582         p = com_polls;
1583         count = 0;
1584         while (p)   {
1585             count ++;
1586             p = p->next;
1587         }
1588         if (count > 0)  {
1589             fds = malloc(sizeof(ico_apf_com_poll_t *) * count);
1590         }
1591         else    {
1592             fds = NULL;
1593         }
1594
1595         p = com_polls;
1596         nfds = 0;
1597         while (fds && p)   {
1598             fds[nfds++] = p;
1599             p = p->next;
1600         }
1601
1602         apfw_trace("ico_apf_com_poll_fd_control: nfds=%d", nfds);
1603         if (nfds > 0)   {
1604             (*ico_apf_pollfd_func)(fds, nfds);
1605         }
1606         if (fds)    free(fds);
1607     }
1608     return ICO_APF_RESOURCE_E_NONE;
1609 }
1610
1611 /*--------------------------------------------------------------------------*/
1612 /**
1613  * @brief   ico_apf_com_poll_fd_event: Notify the changes of file descriptor's state
1614  *
1615  * @param[in]   fd_ctl      The structure of file descriptor's controller
1616  * @param[in]   flags       The user data to be passed to the callback function
1617  * @return      result
1618  * @retval      ICO_APF_RESOURCE_E_NONE             success
1619  */
1620 /*--------------------------------------------------------------------------*/
1621 ICO_APF_API int
1622 ico_apf_com_poll_fd_event(ico_apf_com_poll_t *fd_ctl, int flags)
1623 {
1624     int     st;
1625     ico_apf_com_handle_t    *handle = (ico_apf_com_handle_t *)fd_ctl->apf_fd_control;
1626
1627     if (handle) {
1628         ico_apf_com_dispatch(handle, 0);        /* try to service           */
1629     }
1630     else    {
1631         ico_apf_com_dispatch(NULL, 0);          /* try to service for server*/
1632     }
1633
1634     if (handle) {
1635         /* send if send data exist      */
1636         if ((handle->stail != handle->shead) &&
1637             (handle->wsi_context != NULL) &&
1638             (handle->wsi_connection != NULL))   {
1639             st = handle->shead;
1640             if (handle->shead >= (ICO_APF_RESOURCE_WSOCK_BUFS-1))  {
1641                 handle->shead = 0;
1642             }
1643             else    {
1644                 handle->shead ++;
1645             }
1646             if (ico_apf_com_realsend(handle, handle->sbuf[st])
1647                         != ICO_APF_RESOURCE_E_NONE) {
1648                 apfw_warn("ico_apf_com_poll_fd_event: ico_apf_com_realsend Error");
1649                 handle->shead = st;
1650                 ico_apf_com_dispatch(handle, 10);   /* try to service       */
1651             }
1652             if (handle->stail != handle->shead)    {
1653                 libwebsocket_callback_on_writable(handle->wsi_context,
1654                                                   handle->wsi_connection);
1655             }
1656         }
1657
1658         /* start/stop writable event        */
1659         if ((handle->stail == handle->shead) ||
1660             (handle->wsi_context == NULL) ||
1661             (handle->wsi_connection == NULL))   {
1662             ico_apf_poll_write_event(handle, 0);
1663         }
1664         else    {
1665             libwebsocket_callback_on_writable(handle->wsi_context,
1666                                               handle->wsi_connection);
1667             ico_apf_poll_write_event(handle, 1);
1668         }
1669     }
1670     return ICO_APF_RESOURCE_E_NONE;
1671 }
1672
1673 /*--------------------------------------------------------------------------*/
1674 /**
1675  * @brief   ico_apf_poll_write_event: Write event control for poll
1676  *
1677  * @param[in]   handle          AppsController's handle
1678  * @param[in]   write           set/reset write event
1679  *                              = 0 : reset if not reset
1680  *                              = 1 : set if not set
1681  *                              = 2 : force reset
1682  *                              = 3 : force set
1683  * @return      none
1684  */
1685 /*--------------------------------------------------------------------------*/
1686 static void
1687 ico_apf_poll_write_event(ico_apf_com_handle_t *handle, const int write)
1688 {
1689     ico_apf_com_poll_t  *fds[1];
1690
1691     if (handle->poll)   {
1692         if ((write == 3) || (write == 1)) {
1693             /* set write poll           */
1694             handle->poll->flags |= ICO_APF_COM_POLL_WRITE;
1695             if (ico_apf_pollfd_func)    {
1696                 fds[0] = handle->poll;
1697                 (*ico_apf_pollfd_func)(fds, 1);
1698             }
1699         }
1700         else if ((write == 2) || (write == 0)) {
1701             /* reset write poll         */
1702             handle->poll->flags &= ~ICO_APF_COM_POLL_WRITE;
1703             if (ico_apf_pollfd_func)    {
1704                 fds[0] = handle->poll;
1705                 (*ico_apf_pollfd_func)(fds, 1);
1706             }
1707         }
1708     }
1709 }
1710