display: source clean-up
[sdk/emulator/qemu.git] / tizen / src / ecs / ecs.c
1 /*
2  * Emulator Control Server
3  *
4  * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
5  *
6  * Contact:
7  *  Jinhyung choi   <jinhyung2.choi@samsung.com>
8  *  MunKyu Im       <munkyu.im@samsung.com>
9  *  Daiyoung Kim    <daiyoung777.kim@samsung.com>
10  *  YeongKyoon Lee  <yeongkyoon.lee@samsung.com>
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
25  *
26  * Contributors:
27  * - S-Core Co., Ltd
28  *
29  */
30
31 #include <stdbool.h>
32 #include <pthread.h>
33 #include <stdlib.h>
34
35 #include "hw/qdev.h"
36 #include "net/net.h"
37 #include "ui/console.h"
38
39 #include "qemu-common.h"
40 #include "qemu/queue.h"
41 #include "qemu/sockets.h"
42 #include "qemu/option.h"
43 #include "qemu/timer.h"
44 #include "qemu/main-loop.h"
45 #include "sysemu/char.h"
46 #include "config.h"
47 #include "qapi/qmp/qint.h"
48
49 #include "sdb.h"
50 #include "ecs.h"
51 #include "guest_server.h"
52 #include "emul_state.h"
53
54 #include "genmsg/ecs.pb-c.h"
55
56 #include "debug_ch.h"
57 MULTI_DEBUG_CHANNEL(qemu, ecs);
58
59 #define DEBUG
60
61 #ifndef min
62 #define min(a,b) ((a)<(b)?(a):(b))
63 #endif
64
65 static QTAILQ_HEAD(ECS_ClientHead, ECS_Client)
66 clients = QTAILQ_HEAD_INITIALIZER(clients);
67
68 static ECS_State *current_ecs;
69
70 static void* keepalive_buf;
71 static int payloadsize;
72
73 static int g_client_id = 1;
74
75 static pthread_mutex_t mutex_clilist = PTHREAD_MUTEX_INITIALIZER;
76
77 static int suspend_state = 1;
78
79 void ecs_set_suspend_state(int state)
80 {
81     suspend_state = state;
82 }
83
84 int ecs_get_suspend_state(void)
85 {
86     return suspend_state;
87 }
88
89 int ecs_write(int fd, const uint8_t *buf, int len) {
90     TRACE("write buflen : %d, buf : %s", len, (char*)buf);
91     if (fd < 0) {
92         return -1;
93     }
94
95     return send_all(fd, buf, len);
96 }
97
98 void ecs_client_close(ECS_Client* clii) {
99     if (clii == NULL)
100         return;
101
102     pthread_mutex_lock(&mutex_clilist);
103
104     if (clii->client_fd > 0) {
105         INFO("ecs client closed with fd: %d", clii->client_fd);
106         closesocket(clii->client_fd);
107 #ifndef CONFIG_LINUX
108         FD_CLR(clii->client_fd, &clii->cs->reads);
109 #endif
110         clii->client_fd = -1;
111     }
112
113     QTAILQ_REMOVE(&clients, clii, next);
114
115     g_free(clii);
116     clii = NULL;
117
118     pthread_mutex_unlock(&mutex_clilist);
119 }
120
121 bool send_to_all_client(const char* data, const int len) {
122     TRACE("data len: %d, data: %s", len, data);
123     pthread_mutex_lock(&mutex_clilist);
124
125     ECS_Client *clii;
126
127     QTAILQ_FOREACH(clii, &clients, next)
128     {
129         send_to_client(clii->client_fd, data, len);
130     }
131     pthread_mutex_unlock(&mutex_clilist);
132
133     return true;
134 }
135
136 void send_to_single_client(ECS_Client *clii, const char* data, const int len)
137 {
138     pthread_mutex_lock(&mutex_clilist);
139     send_to_client(clii->client_fd, data, len);
140     pthread_mutex_unlock(&mutex_clilist);
141 }
142
143 void send_to_client(int fd, const char* data, const int len)
144 {
145     ecs_write(fd, (const uint8_t*) data, len);
146 }
147
148 void read_val_short(const char* data, unsigned short* ret_val) {
149     memcpy(ret_val, data, sizeof(unsigned short));
150 }
151
152 void read_val_char(const char* data, unsigned char* ret_val) {
153     memcpy(ret_val, data, sizeof(unsigned char));
154 }
155
156 void read_val_str(const char* data, char* ret_val, int len) {
157     memcpy(ret_val, data, len);
158 }
159
160 bool ntf_to_control(const char* data, const int len) {
161     return true;
162 }
163
164 bool ntf_to_monitor(const char* data, const int len) {
165     return true;
166 }
167
168 void print_binary(const char* data, const int len) {
169     int i;
170     printf("[DATA: ");
171     for(i = 0; i < len; i++) {
172         if(i == len - 1) {
173             printf("%02x]\n", data[i]);
174         } else {
175             printf("%02x,", data[i]);
176         }
177     }
178 }
179
180 void ecs_make_header(QDict* obj, type_length length, type_group group,
181         type_action action) {
182     qdict_put(obj, "length", qint_from_int((int64_t )length));
183     qdict_put(obj, "group", qint_from_int((int64_t )group));
184     qdict_put(obj, "action", qint_from_int((int64_t )action));
185 }
186
187 static Monitor *monitor_create(void) {
188     Monitor *mon;
189
190     mon = g_malloc0(sizeof(*mon));
191     if (NULL == mon) {
192         ERR("monitor allocation failed.");
193         return NULL;
194     }
195
196     return mon;
197 }
198
199 static void ecs_close(ECS_State *cs) {
200     ECS_Client *clii;
201     INFO("### Good bye! ECS ###");
202
203     if (cs == NULL)
204         return;
205
206     if (0 <= cs->listen_fd) {
207         INFO("close listen_fd: %d", cs->listen_fd);
208         closesocket(cs->listen_fd);
209         cs->listen_fd = -1;
210     }
211
212     if (cs->mon != NULL) {
213         g_free(cs->mon);
214         cs->mon = NULL;
215     }
216
217     if (keepalive_buf) {
218         g_free(keepalive_buf);
219     }
220
221     if (cs->alive_timer != NULL) {
222         timer_del(cs->alive_timer);
223         cs->alive_timer = NULL;
224     }
225
226     QTAILQ_FOREACH(clii, &clients, next)
227     {
228         ecs_client_close(clii);
229     }
230
231     g_free(cs);
232     cs = NULL;
233     current_ecs = NULL;
234 }
235
236 #ifndef _WIN32
237 static ssize_t ecs_recv(int fd, char *buf, size_t len) {
238     struct msghdr msg = { NULL, };
239     struct iovec iov[1];
240     union {
241         struct cmsghdr cmsg;
242         char control[CMSG_SPACE(sizeof(int))];
243     } msg_control;
244     int flags = 0;
245
246     iov[0].iov_base = buf;
247     iov[0].iov_len = len;
248
249     msg.msg_iov = iov;
250     msg.msg_iovlen = 1;
251     msg.msg_control = &msg_control;
252     msg.msg_controllen = sizeof(msg_control);
253
254 #ifdef MSG_CMSG_CLOEXEC
255     flags |= MSG_CMSG_CLOEXEC;
256 #endif
257     return recvmsg(fd, &msg, flags);
258 }
259
260 #else
261 static ssize_t ecs_recv(int fd, char *buf, size_t len)
262 {
263     return qemu_recv(fd, buf, len, 0);
264 }
265 #endif
266
267
268 static void reset_sbuf(sbuf* sbuf)
269 {
270     memset(sbuf->_buf, 0, 4096);
271     sbuf->_use = 0;
272     sbuf->_netlen = 0;
273 }
274
275 static void ecs_read(ECS_Client *cli) {
276
277     int read = 0;
278     int to_read_bytes = 0;
279
280     if (cli == NULL)
281     {
282         ERR("client is null.");
283         return;
284     }
285 #ifndef __WIN32
286     if (ioctl(cli->client_fd, FIONREAD, &to_read_bytes) < 0)
287     {
288         ERR("ioctl failed");
289         return;
290     }
291 #else
292     unsigned long to_read_bytes_long = 0;
293     if (ioctlsocket(cli->client_fd, FIONREAD, &to_read_bytes_long) < 0)
294     {
295         ERR("ioctl failed");
296          return;
297     }
298     to_read_bytes = (int)to_read_bytes_long;
299 #endif
300
301     if (to_read_bytes == 0) {
302         ERR("ioctl FIONREAD: 0\n");
303         goto fail;
304     }
305
306     if (cli->sbuf._netlen == 0)
307     {
308         if (to_read_bytes < 4)
309         {
310             //LOG("insufficient data size to read");
311             return;
312         }
313
314         long payloadsize = 0;
315         read = ecs_recv(cli->client_fd, (char*) &payloadsize, 4);
316
317         if (read < 4)
318         {
319             ERR("insufficient header size");
320             goto fail;
321         }
322
323         payloadsize = ntohl(payloadsize);
324
325         cli->sbuf._netlen = payloadsize;
326
327         TRACE("payload size: %ld\n", payloadsize);
328
329         to_read_bytes -= 4;
330     }
331
332     if (to_read_bytes == 0)
333         return;
334
335
336     to_read_bytes = min(to_read_bytes, cli->sbuf._netlen - cli->sbuf._use);
337
338     read = ecs_recv(cli->client_fd, (char*)(cli->sbuf._buf + cli->sbuf._use), to_read_bytes);
339     if (read == 0)
340         goto fail;
341
342
343     cli->sbuf._use += read;
344
345
346     if (cli->sbuf._netlen == cli->sbuf._use)
347     {
348         handle_protobuf_msg(cli, (char*)cli->sbuf._buf, cli->sbuf._use);
349         reset_sbuf(&cli->sbuf);
350     }
351
352     return;
353 fail:
354     ecs_client_close(cli);
355 }
356
357 #ifdef CONFIG_LINUX
358 static void epoll_cli_add(ECS_State *cs, int fd) {
359     struct epoll_event events;
360
361     /* event control set for read event */
362     events.events = EPOLLIN;
363     events.data.fd = fd;
364
365     if (epoll_ctl(cs->epoll_fd, EPOLL_CTL_ADD, fd, &events) < 0) {
366         ERR("Epoll control fails.in epoll_cli_add.");
367     }
368 }
369 #endif
370
371 static ECS_Client *ecs_find_client(int fd) {
372     ECS_Client *clii;
373
374     QTAILQ_FOREACH(clii, &clients, next)
375     {
376         if (clii->client_fd == fd)
377             return clii;
378     }
379     return NULL;
380 }
381
382 ECS_Client *find_client(unsigned char id, unsigned char type) {
383     ECS_Client *clii;
384
385     QTAILQ_FOREACH(clii, &clients, next)
386     {
387         if (clii->client_id == id && clii->client_type == type)
388             return clii;
389     }
390     return NULL;
391 }
392
393 static int ecs_add_client(ECS_State *cs, int fd) {
394
395     ECS_Client *clii = g_malloc0(sizeof(ECS_Client));
396     if (NULL == clii) {
397         ERR("ECS_Client allocation failed.");
398         return -1;
399     }
400
401     reset_sbuf(&clii->sbuf);
402
403     qemu_set_nonblock(fd);
404
405     clii->client_fd = fd;
406     clii->cs = cs;
407     clii->client_type = TYPE_NONE;
408
409     ecs_json_message_parser_init(&clii->parser, handle_qmp_command, clii);
410
411 #ifdef CONFIG_LINUX
412     epoll_cli_add(cs, fd);
413 #else
414     FD_SET(fd, &cs->reads);
415 #endif
416
417     pthread_mutex_lock(&mutex_clilist);
418
419     QTAILQ_INSERT_TAIL(&clients, clii, next);
420
421     INFO("Add an ecs client. fd: %d", fd);
422
423     pthread_mutex_unlock(&mutex_clilist);
424
425 //    send_ecs_version_check(clii);
426
427     return 0;
428 }
429
430 static void ecs_accept(ECS_State *cs) {
431     struct sockaddr_in saddr;
432 #ifndef _WIN32
433     struct sockaddr_un uaddr;
434 #endif
435     struct sockaddr *addr;
436     socklen_t len;
437     int fd;
438
439     for (;;) {
440 #ifndef _WIN32
441         if (cs->is_unix) {
442             len = sizeof(uaddr);
443             addr = (struct sockaddr *) &uaddr;
444         } else
445 #endif
446         {
447             len = sizeof(saddr);
448             addr = (struct sockaddr *) &saddr;
449         }
450         fd = qemu_accept(cs->listen_fd, addr, &len);
451         if (0 > fd && EINTR != errno) {
452             return;
453         } else if (0 <= fd) {
454             break;
455         }
456     }
457     if (0 > ecs_add_client(cs, fd)) {
458         ERR("failed to add client.");
459     }
460 }
461
462 #ifdef CONFIG_LINUX
463 static void epoll_init(ECS_State *cs) {
464     struct epoll_event events;
465
466     cs->epoll_fd = epoll_create(MAX_EVENTS);
467     if (cs->epoll_fd < 0) {
468         closesocket(cs->listen_fd);
469     }
470
471     events.events = EPOLLIN;
472     events.data.fd = cs->listen_fd;
473
474     if (epoll_ctl(cs->epoll_fd, EPOLL_CTL_ADD, cs->listen_fd, &events) < 0) {
475         close(cs->listen_fd);
476         close(cs->epoll_fd);
477     }
478 }
479 #endif
480
481 static void send_keep_alive_msg(ECS_Client *clii) {
482     send_to_single_client(clii, keepalive_buf, payloadsize);
483 }
484
485 static void make_keep_alive_msg(void) {
486     int len_pack = 0;
487     char msg [5] = {'s','e','l','f'};
488
489     ECS__Master master = ECS__MASTER__INIT;
490     ECS__KeepAliveReq req = ECS__KEEP_ALIVE_REQ__INIT;
491
492     req.time_str = (char*) g_malloc(5);
493
494     strncpy(req.time_str, msg, 4);
495
496     master.type = ECS__MASTER__TYPE__KEEPALIVE_REQ;
497     master.keepalive_req = &req;
498
499     len_pack = ecs__master__get_packed_size(&master);
500     payloadsize = len_pack + 4;
501
502     keepalive_buf = g_malloc(len_pack + 4);
503     if (!keepalive_buf) {
504         ERR("keep alive message creation is failed.");
505         return;
506     }
507
508     ecs__master__pack(&master, keepalive_buf + 4);
509
510     len_pack = htonl(len_pack);
511     memcpy(keepalive_buf, &len_pack, 4);
512 }
513
514 static void alive_checker(void *opaque) {
515
516     ECS_Client *clii;
517
518     if (NULL != current_ecs && !current_ecs->ecs_running) {
519         return;
520     }
521
522     QTAILQ_FOREACH(clii, &clients, next)
523     {
524         if (1 == clii->keep_alive) {
525             INFO("get client fd %d - keep alive fail", clii->client_fd);
526             ecs_client_close(clii);
527             continue;
528         }
529         TRACE("set client fd %d - keep alive 1", clii->client_fd);
530         clii->keep_alive = 1;
531         send_keep_alive_msg(clii);
532     }
533
534     if (current_ecs == NULL) {
535         ERR("alive checking is failed because current ecs is null.");
536         return;
537     }
538
539     timer_mod(current_ecs->alive_timer,
540             qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + get_ticks_per_sec() * TIMER_ALIVE_S);
541
542 }
543
544 static int socket_initialize(ECS_State *cs, QemuOpts *opts) {
545     int fd = -1;
546     Error *local_err = NULL;
547
548     fd = inet_listen_opts(opts, 0, &local_err);
549     if (0 > fd || error_is_set(&local_err)) {
550         qerror_report_err(local_err);
551         error_free(local_err);
552         return -1;
553     }
554
555     INFO("Listen fd is %d", fd);
556
557     qemu_set_nonblock(fd);
558
559     cs->listen_fd = fd;
560
561 #ifdef CONFIG_LINUX
562     epoll_init(cs);
563 #else
564     FD_ZERO(&cs->reads);
565     FD_SET(fd, &cs->reads);
566 #endif
567
568     make_keep_alive_msg();
569
570     cs->alive_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, alive_checker, cs);
571
572     timer_mod(cs->alive_timer,
573             qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + get_ticks_per_sec() * TIMER_ALIVE_S);
574
575     return 0;
576 }
577
578 #ifdef CONFIG_LINUX
579 static int ecs_loop(ECS_State *cs) {
580     int i, nfds;
581
582     nfds = epoll_wait(cs->epoll_fd, cs->events, MAX_EVENTS, 100);
583     if (0 == nfds) {
584         return 0;
585     }
586
587     if (0 > nfds) {
588         if (errno == EINTR)
589             return 0;
590         perror("epoll wait error");
591         return -1;
592     }
593
594     for (i = 0; i < nfds; i++) {
595         if (cs->events[i].data.fd == cs->listen_fd) {
596             ecs_accept(cs);
597             continue;
598         }
599         ecs_read(ecs_find_client(cs->events[i].data.fd));
600     }
601
602     return 0;
603 }
604 #elif defined(CONFIG_WIN32)
605 static int ecs_loop(ECS_State *cs)
606 {
607     int index = 0;
608     TIMEVAL timeout;
609     fd_set temps = cs->reads;
610
611     timeout.tv_sec = 5;
612     timeout.tv_usec = 0;
613
614     if (select(0, &temps, 0, 0, &timeout) < 0) {
615         ERR("select error.");
616         return -1;
617     }
618
619     for (index = 0; index < cs->reads.fd_count; index++) {
620         if (cs->reads.fd_array == NULL)
621             continue;
622
623         if (FD_ISSET(cs->reads.fd_array[index], &temps)) {
624             if (cs->reads.fd_array[index] == cs->listen_fd) {
625                 ecs_accept(cs);
626                 continue;
627             }
628
629             ecs_read(ecs_find_client(cs->reads.fd_array[index]));
630         }
631     }
632
633     return 0;
634 }
635 #elif defined(CONFIG_DARWIN)
636 static int ecs_loop(ECS_State *cs)
637 {
638     int index = 0;
639     int res = 0;
640     struct timeval timeout;
641     fd_set temps = cs->reads;
642
643     timeout.tv_sec = 5;
644     timeout.tv_usec = 0;
645
646     if ((res = select(MAX_FD_NUM + 1, &temps, NULL, NULL, &timeout)) < 0) {
647         ERR("select failed..");
648         return -1;
649     }
650
651     for (index = 0; index < MAX_FD_NUM; index ++) {
652         if (FD_ISSET(index, &temps)) {
653             if (index == cs->listen_fd) {
654                 ecs_accept(cs);
655                 continue;
656             }
657
658             ecs_read(ecs_find_client(index));
659         }
660     }
661
662     return 0;
663 }
664
665 #endif
666
667 static void* ecs_initialize(void* args) {
668     int ret = 1;
669     ECS_State *cs = NULL;
670     QemuOpts *opts = NULL;
671     Error *local_err = NULL;
672     Monitor* mon = NULL;
673     char host_port[16];
674     int port = 0;
675
676     INFO("ecs starts initializing.");
677
678     opts = qemu_opts_create(qemu_find_opts(ECS_OPTS_NAME), ECS_OPTS_NAME, 1, &local_err);
679     if (error_is_set(&local_err)) {
680         qerror_report_err(local_err);
681         error_free(local_err);
682         return NULL;
683     }
684
685     qemu_opt_set(opts, "host", HOST_LISTEN_ADDR);
686
687     cs = g_malloc0(sizeof(ECS_State));
688     if (NULL == cs) {
689         ERR("ECS_State allocation failed.");
690         return NULL;
691     }
692     port = get_emul_ecs_port();
693     INFO("ecs port: %d", port);
694     sprintf(host_port, "%d", port);
695
696     qemu_opt_set(opts, "port", host_port);
697     ret = socket_initialize(cs, opts);
698     if (ret < 0) {
699         ERR("Socket initialization is failed.");
700         ecs_close(cs);
701         return NULL;
702     }
703
704     mon = monitor_create();
705     if (NULL == mon) {
706         ERR("monitor initialization failed.");
707         ecs_close(cs);
708         return NULL;
709     }
710
711     cs->mon = mon;
712     current_ecs = cs;
713     cs->ecs_running = 1;
714
715     TRACE("ecs_loop entered.");
716     while (cs->ecs_running) {
717         ret = ecs_loop(cs);
718         if (0 > ret) {
719             ecs_close(cs);
720             break;
721         }
722     }
723     TRACE("ecs_loop exited.");
724
725     return NULL;
726 }
727
728 int stop_ecs(void) {
729     INFO("ecs is closing.");
730     if (NULL != current_ecs) {
731         current_ecs->ecs_running = 0;
732         ecs_close(current_ecs);
733     }
734
735     pthread_mutex_destroy(&mutex_clilist);
736
737     return 0;
738 }
739
740 int start_ecs(void) {
741     pthread_t thread_id;
742
743     if (0 != pthread_create(&thread_id, NULL, ecs_initialize, NULL)) {
744         ERR("pthread creation failed.");
745         return -1;
746     }
747     return 0;
748 }
749
750 bool handle_protobuf_msg(ECS_Client* cli, char* data, int len)
751 {
752     ECS__Master* master = ecs__master__unpack(NULL, (size_t)len, (const uint8_t*)data);
753     if (!master)
754         return false;
755
756     if (master->type == ECS__MASTER__TYPE__INJECTOR_REQ)
757     {
758         ECS__InjectorReq* msg = master->injector_req;
759         if (!msg)
760             goto fail;
761         msgproc_injector_req(cli, msg);
762     }
763     else if (master->type == ECS__MASTER__TYPE__MONITOR_REQ)
764     {
765         ECS__MonitorReq* msg = master->monitor_req;
766         if (!msg)
767             goto fail;
768         msgproc_monitor_req(cli, msg);
769     }
770     else if (master->type == ECS__MASTER__TYPE__DEVICE_REQ)
771     {
772         cli->client_type = TYPE_ECP;
773         ECS__DeviceReq* msg = master->device_req;
774         if (!msg)
775             goto fail;
776         msgproc_device_req(cli, msg);
777     }
778     else if (master->type == ECS__MASTER__TYPE__NFC_REQ)
779     {
780         ECS__NfcReq* msg = master->nfc_req;
781         if (!msg)
782             goto fail;
783
784         pthread_mutex_lock(&mutex_clilist);
785         if(cli->client_type == TYPE_NONE) {
786             if (!strncmp(msg->category, MSG_TYPE_NFC, 3)) {
787                 QTAILQ_REMOVE(&clients, cli, next);
788                 cli->client_type = TYPE_ECP;
789                 if(g_client_id > 255) {
790                     g_client_id = 1;
791                 }
792                 cli->client_id = g_client_id++;
793
794                 QTAILQ_INSERT_TAIL(&clients, cli, next);
795             }
796             else if (!strncmp(msg->category, MSG_TYPE_SIMUL_NFC, 9)) {
797                 QTAILQ_REMOVE(&clients, cli, next);
798                 cli->client_type = TYPE_SIMUL_NFC;
799                 if(g_client_id > 255) {
800                     g_client_id = 1;
801                 }
802                 cli->client_id = g_client_id++;
803                 QTAILQ_INSERT_TAIL(&clients, cli, next);
804             }
805             else {
806                 ERR("unsupported category is found: %s", msg->category);
807                 pthread_mutex_unlock(&mutex_clilist);
808                 goto fail;
809             }
810         }
811         pthread_mutex_unlock(&mutex_clilist);
812
813         msgproc_nfc_req(cli, msg);
814     }
815 #if 0
816     else if (master->type == ECS__MASTER__TYPE__CHECKVERSION_REQ)
817     {
818         ECS__CheckVersionReq* msg = master->checkversion_req;
819         if (!msg)
820             goto fail;
821         msgproc_checkversion_req(cli, msg);
822     }
823 #endif
824     else if (master->type == ECS__MASTER__TYPE__KEEPALIVE_ANS)
825     {
826         ECS__KeepAliveAns* msg = master->keepalive_ans;
827         if (!msg)
828             goto fail;
829         msgproc_keepalive_ans(cli, msg);
830     }
831     else if (master->type == ECS__MASTER__TYPE__TETHERING_REQ)
832     {
833         ECS__TetheringReq* msg = master->tethering_req;
834         if (!msg)
835             goto fail;
836         msgproc_tethering_req(cli, msg);
837     }
838
839     ecs__master__free_unpacked(master, NULL);
840     return true;
841 fail:
842     ERR("invalid message type : %d", master->type);
843     ecs__master__free_unpacked(master, NULL);
844     return false;
845 }