Update SMACK, Fix a crash of terminating sequence, etc, ...
[apps/livebox/data-provider-master.git] / src / service_common.c
1 /*
2  * Copyright 2013  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.1 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://floralicense.org/license/
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #define _GNU_SOURCE
17 #include <stdio.h>
18 #include <pthread.h>
19 #include <secure_socket.h>
20 #include <packet.h>
21 #include <errno.h>
22 #include <sys/time.h>
23 #include <sys/types.h>
24 #include <sys/timerfd.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27
28 #include <dlog.h>
29 #include <Eina.h>
30
31 #include "service_common.h"
32 #include "util.h"
33 #include "debug.h"
34 #include "conf.h"
35
36 #define EVT_CH          'e'
37 #define EVT_END_CH      'x'
38
39 int errno;
40
41 struct service_event_item {
42         enum {
43                 SERVICE_EVENT_TIMER,
44         } type;
45
46         union {
47                 struct {
48                         int fd;
49                 } timer;
50         } info;
51
52         int (*event_cb)(struct service_context *svc_cx, void *data);
53         void *cbdata;
54 };
55
56 /*!
57  * \note
58  * Server information and global (only in this file-scope) variables are defined
59  */
60 struct service_context {
61         pthread_t server_thid; /*!< Server thread Id */
62         int fd; /*!< Server socket handle */
63
64         Eina_List *tcb_list; /*!< TCB list, list of every thread for client connections */
65
66         Eina_List *packet_list;
67         pthread_mutex_t packet_list_lock;
68         int evt_pipe[PIPE_MAX];
69         int tcb_pipe[PIPE_MAX];
70
71         int (*service_thread_main)(struct tcb *tcb, struct packet *packet, void *data);
72         void *service_thread_data;
73
74         Eina_List *event_list;
75 };
76
77 struct packet_info {
78         struct tcb *tcb;
79         struct packet *packet;
80 };
81
82 /*!
83  * \note
84  * Thread Control Block
85  * - The main server will create a thread for every client connections.
86  *   When a new client is comming to us, this TCB block will be allocated and initialized.
87  */
88 struct tcb { /* Thread controll block */
89         struct service_context *svc_ctx;
90         pthread_t thid; /*!< Thread Id */
91         int fd; /*!< Connection handle */
92         enum tcb_type type;
93         int ctrl_pipe[PIPE_MAX];
94 };
95
96 /*!
97  * Do services for clients
98  * Routing packets to destination processes.
99  * CLIENT THREAD
100  */
101 static void *client_packet_pump_main(void *data)
102 {
103         struct tcb *tcb = data;
104         struct service_context *svc_ctx = tcb->svc_ctx;
105         struct packet *packet;
106         fd_set set;
107         char *ptr;
108         int size;
109         int packet_offset;
110         int recv_offset;
111         int pid;
112         int ret;
113         int fd;
114         char evt_ch = EVT_CH;
115         enum {
116                 RECV_INIT,
117                 RECV_HEADER,
118                 RECV_PAYLOAD,
119                 RECV_DONE,
120         } recv_state;
121         struct packet_info *packet_info;
122         Eina_List *l;
123
124         ret = 0;
125         recv_state = RECV_INIT;
126         /*!
127          * \note
128          * To escape from the switch statement, we use this ret value
129          */
130         while (ret == 0) {
131                 FD_ZERO(&set);
132                 FD_SET(tcb->fd, &set);
133                 FD_SET(tcb->ctrl_pipe[PIPE_READ], &set);
134                 fd = tcb->fd > tcb->ctrl_pipe[PIPE_READ] ? tcb->fd : tcb->ctrl_pipe[PIPE_READ];
135                 ret = select(fd + 1, &set, NULL, NULL, NULL);
136                 if (ret < 0) {
137                         ret = -errno;
138                         if (errno == EINTR) {
139                                 DbgPrint("INTERRUPTED\n");
140                                 ret = 0;
141                                 continue;
142                         }
143                         ErrPrint("Error: %s\n", strerror(errno));
144                         free(ptr);
145                         ptr = NULL;
146                         break;
147                 } else if (ret == 0) {
148                         ErrPrint("Timeout\n");
149                         ret = -ETIMEDOUT;
150                         free(ptr);
151                         ptr = NULL;
152                         break;
153                 }
154
155                 if (FD_ISSET(tcb->ctrl_pipe[PIPE_READ], &set)) {
156                         DbgPrint("Thread is canceled\n");
157                         ret = -ECANCELED;
158                         free(ptr);
159                         ptr = NULL;
160                         break;
161                 }
162
163                 if (!FD_ISSET(tcb->fd, &set)) {
164                         ErrPrint("Unexpected handler is toggled\n");
165                         ret = -EINVAL;
166                         free(ptr);
167                         ptr = NULL;
168                         break;
169                 }
170                 
171                 /*!
172                  * \TODO
173                  * Service!!! Receive packet & route packet
174                  */
175                 switch (recv_state) {
176                 case RECV_INIT:
177                         size = packet_header_size();
178                         packet_offset = 0;
179                         recv_offset = 0;
180                         packet = NULL;
181                         ptr = malloc(size);
182                         if (!ptr) {
183                                 ErrPrint("Heap: %s\n", strerror(errno));
184                                 ret = -ENOMEM;
185                                 break;
186                         }
187                         recv_state = RECV_HEADER;
188                         /* Go through, don't break from here */
189                 case RECV_HEADER:
190                         ret = secure_socket_recv(tcb->fd, ptr, size - recv_offset, &pid);
191                         if (ret <= 0) {
192                                 if (ret == 0)
193                                         ret = -ECANCELED;
194                                 free(ptr);
195                                 ptr = NULL;
196                                 break;
197                         }
198
199                         recv_offset += ret;
200                         ret = 0;
201
202                         if (recv_offset == size) {
203                                 packet = packet_build(packet, packet_offset, ptr, size);
204                                 free(ptr);
205                                 ptr = NULL;
206                                 if (!packet) {
207                                         ret = -EFAULT;
208                                         break;
209                                 }
210
211                                 packet_offset += recv_offset;
212
213                                 size = packet_payload_size(packet);
214                                 if (size <= 0) {
215                                         recv_state = RECV_DONE;
216                                         recv_offset = 0;
217                                         break;
218                                 }
219
220                                 recv_state = RECV_PAYLOAD;
221                                 recv_offset = 0;
222
223                                 ptr = malloc(size);
224                                 if (!ptr) {
225                                         ErrPrint("Heap: %s\n", strerror(errno));
226                                         ret = -ENOMEM;
227                                 }
228                         }
229                         break;
230                 case RECV_PAYLOAD:
231                         ret = secure_socket_recv(tcb->fd, ptr, size - recv_offset, &pid);
232                         if (ret <= 0) {
233                                 if (ret == 0)
234                                         ret = -ECANCELED;
235                                 free(ptr);
236                                 ptr = NULL;
237                                 break;
238                         }
239
240                         recv_offset += ret;
241                         ret = 0;
242
243                         if (recv_offset == size) {
244                                 packet = packet_build(packet, packet_offset, ptr, size);
245                                 free(ptr);
246                                 ptr = NULL;
247                                 if (!packet) {
248                                         ret = -EFAULT;
249                                         break;
250                                 }
251
252                                 packet_offset += recv_offset;
253
254                                 recv_state = RECV_DONE;
255                                 recv_offset = 0;
256                         }
257                         break;
258                 case RECV_DONE:
259                 default:
260                         /* Dead code */
261                         break;
262                 }
263
264                 if (recv_state == RECV_DONE) {
265                         /*!
266                          * Push this packet to the packet list with TCB
267                          * Then the service main function will get this.
268                          */
269                         packet_info = malloc(sizeof(*packet_info));
270                         if (!packet_info) {
271                                 ret = -errno;
272                                 ErrPrint("Heap: %s\n", strerror(errno));
273                                 packet_destroy(packet);
274                                 break;
275                         }
276
277                         packet_info->packet = packet;
278                         packet_info->tcb = tcb;
279
280                         CRITICAL_SECTION_BEGIN(&svc_ctx->packet_list_lock);
281                         svc_ctx->packet_list = eina_list_append(svc_ctx->packet_list, packet_info);
282                         CRITICAL_SECTION_END(&svc_ctx->packet_list_lock);
283
284                         if (write(svc_ctx->evt_pipe[PIPE_WRITE], &evt_ch, sizeof(evt_ch)) != sizeof(evt_ch)) {
285                                 ret = -errno;
286                                 ErrPrint("Unable to write a pipe: %s\n", strerror(errno));
287                                 CRITICAL_SECTION_BEGIN(&svc_ctx->packet_list_lock);
288                                 svc_ctx->packet_list = eina_list_remove(svc_ctx->packet_list, packet_info);
289                                 CRITICAL_SECTION_END(&svc_ctx->packet_list_lock);
290
291                                 packet_destroy(packet);
292                                 free(packet_info);
293                                 ErrPrint("Terminate thread: %p\n", tcb);
294                                 break;
295                         } else {
296                                 DbgPrint("Packet received: %d bytes\n", packet_offset);
297                                 recv_state = RECV_INIT;
298                         }
299                 }
300         }
301
302         CRITICAL_SECTION_BEGIN(&svc_ctx->packet_list_lock);
303         EINA_LIST_FOREACH(svc_ctx->packet_list, l, packet_info) {
304                 if (packet_info->tcb == tcb) {
305                         DbgPrint("Reset ptr of the TCB[%p] in the list of packet info\n", tcb);
306                         packet_info->tcb = NULL;
307                 }
308         }
309         CRITICAL_SECTION_END(&svc_ctx->packet_list_lock);
310
311         /*!
312          * \note
313          * Emit a signal to collect this TCB from the SERVER THREAD.
314          */
315         if (write(svc_ctx->tcb_pipe[PIPE_WRITE], &tcb, sizeof(tcb)) != sizeof(tcb))
316                 ErrPrint("Unable to write pipe: %s\n", strerror(errno));
317
318         return (void *)ret;
319 }
320
321 /*!
322  * \note
323  * SERVER THREAD
324  */
325 static inline struct tcb *tcb_create(struct service_context *svc_ctx, int fd)
326 {
327         struct tcb *tcb;
328         int status;
329
330         tcb = malloc(sizeof(*tcb));
331         if (!tcb) {
332                 ErrPrint("Heap: %s\n", strerror(errno));
333                 return NULL;
334         }
335
336         if (pipe2(tcb->ctrl_pipe, O_NONBLOCK | O_CLOEXEC) < 0) {
337                 ErrPrint("pipe2: %s\n", strerror(errno));
338                 free(tcb);
339                 return NULL;
340         }
341
342         tcb->fd = fd;
343         tcb->svc_ctx = svc_ctx;
344         tcb->type = TCB_CLIENT_TYPE_APP;
345
346         DbgPrint("Create a new service thread [%d]\n", fd);
347         status = pthread_create(&tcb->thid, NULL, client_packet_pump_main, tcb);
348         if (status != 0) {
349                 ErrPrint("Unable to create a new thread: %s\n", strerror(status));
350                 CLOSE_PIPE(tcb->ctrl_pipe);
351                 free(tcb);
352                 return NULL;
353         }
354
355         svc_ctx->tcb_list = eina_list_append(svc_ctx->tcb_list, tcb);
356         return tcb;
357 }
358
359 /*!
360  * \note
361  * SERVER THREAD
362  */
363 static inline void tcb_teminate_all(struct service_context *svc_ctx)
364 {
365         struct tcb *tcb;
366         void *ret;
367         int status;
368         char ch = EVT_END_CH;
369
370         /*!
371          * We don't need to make critical section on here.
372          * If we call this after terminate the server thread first.
373          * Then there is no other thread to access tcb_list.
374          */
375         EINA_LIST_FREE(svc_ctx->tcb_list, tcb) {
376                 /*!
377                  * ASSERT(tcb->fd >= 0);
378                  */
379                 if (write(tcb->ctrl_pipe[PIPE_WRITE], &ch, sizeof(ch)) != sizeof(ch))
380                         ErrPrint("write: %s\n", strerror(errno));
381
382                 status = pthread_join(tcb->thid, &ret);
383                 if (status != 0)
384                         ErrPrint("Unable to join a thread: %s\n", strerror(status));
385                 else
386                         DbgPrint("Thread returns: %d\n", (int)ret);
387
388                 secure_socket_destroy_handle(tcb->fd);
389
390                 CLOSE_PIPE(tcb->ctrl_pipe);
391                 free(tcb);
392         }
393 }
394
395 /*!
396  * \note
397  * SERVER THREAD
398  */
399 static inline void tcb_destroy(struct service_context *svc_ctx, struct tcb *tcb)
400 {
401         void *ret;
402         int status;
403         char ch = EVT_END_CH;
404
405         svc_ctx->tcb_list = eina_list_remove(svc_ctx->tcb_list, tcb);
406         /*!
407          * ASSERT(tcb->fd >= 0);
408          * Close the connection, and then collecting the return value of thread
409          */
410         if (write(tcb->ctrl_pipe[PIPE_WRITE], &ch, sizeof(ch)) != sizeof(ch))
411                 ErrPrint("write: %s\n", strerror(errno));
412
413         status = pthread_join(tcb->thid, &ret);
414         if (status != 0)
415                 ErrPrint("Unable to join a thread: %s\n", strerror(status));
416         else
417                 DbgPrint("Thread returns: %d\n", (int)ret);
418
419         secure_socket_destroy_handle(tcb->fd);
420
421         CLOSE_PIPE(tcb->ctrl_pipe);
422         free(tcb);
423 }
424
425 /*!
426  * \note
427  * SERVER THREAD
428  */
429 static inline int update_fdset(struct service_context *svc_ctx, fd_set *set)
430 {
431         Eina_List *l;
432         struct service_event_item *item;
433         int fd = 0;
434
435         FD_ZERO(set);
436
437         FD_SET(svc_ctx->fd, set);
438         fd = svc_ctx->fd;
439
440         FD_SET(svc_ctx->tcb_pipe[PIPE_READ], set);
441         if (svc_ctx->tcb_pipe[PIPE_READ] > fd)
442                 fd = svc_ctx->tcb_pipe[PIPE_READ];
443
444         FD_SET(svc_ctx->evt_pipe[PIPE_READ], set);
445         if (svc_ctx->evt_pipe[PIPE_READ] > fd)
446                 fd = svc_ctx->evt_pipe[PIPE_READ];
447
448         EINA_LIST_FOREACH(svc_ctx->event_list, l, item) {
449                 if (item->type == SERVICE_EVENT_TIMER) {
450                         FD_SET(item->info.timer.fd, set);
451                         if (fd < item->info.timer.fd)
452                                 fd = item->info.timer.fd;
453                 }
454         }
455
456         return fd + 1;
457 }
458
459 /*!
460  * \note
461  * SERVER THREAD
462  */
463 static inline void processing_timer_event(struct service_context *svc_ctx, fd_set *set)
464 {
465         uint64_t expired_count;
466         Eina_List *l;
467         Eina_List *n;
468         struct service_event_item *item;
469
470         EINA_LIST_FOREACH_SAFE(svc_ctx->event_list, l, n, item) {
471                 switch (item->type) {
472                 case SERVICE_EVENT_TIMER:
473                         if (!FD_ISSET(item->info.timer.fd, set))
474                                 break;
475
476                         if (read(item->info.timer.fd, &expired_count, sizeof(expired_count)) == sizeof(expired_count)) {
477                                 DbgPrint("Expired %d times\n", expired_count);
478                                 if (item->event_cb(svc_ctx, item->cbdata) >= 0)
479                                         break;
480                         } else {
481                                 ErrPrint("read: %s\n", strerror(errno));
482                         }
483
484                         if (!eina_list_data_find(svc_ctx->event_list, item))
485                                 break;
486
487                         svc_ctx->event_list = eina_list_remove(svc_ctx->event_list, item);
488                         if (close(item->info.timer.fd) < 0)
489                                 ErrPrint("close: %s\n", strerror(errno));
490                         free(item);
491                         break;
492                 default:
493                         ErrPrint("Unknown event: %d\n", item->type);
494                         break;
495                 }
496         }
497 }
498
499 /*!
500  * Accept new client connections
501  * And create a new thread for service.
502  *
503  * Create Client threads & Destroying them
504  * SERVER THREAD
505  */
506 static void *server_main(void *data)
507 {
508         struct service_context *svc_ctx = data;
509         fd_set set;
510         fd_set except_set;
511         int ret;
512         int client_fd;
513         struct tcb *tcb;
514         int fd;
515         char evt_ch;
516         struct packet_info *packet_info;
517
518         DbgPrint("Server thread is activated\n");
519         while (1) {
520                 fd = update_fdset(svc_ctx, &set);
521                 memcpy(&except_set, &set, sizeof(set));
522
523                 ret = select(fd, &set, NULL, &except_set, NULL);
524                 if (ret < 0) {
525                         ret = -errno;
526                         if (errno == EINTR) {
527                                 DbgPrint("INTERRUPTED\n");
528                                 continue;
529                         }
530                         ErrPrint("Error: %s\n", strerror(errno));
531                         break;
532                 } else if (ret == 0) {
533                         ErrPrint("Timeout\n");
534                         ret = -ETIMEDOUT;
535                         break;
536                 }
537
538                 if (FD_ISSET(svc_ctx->fd, &set)) {
539                         client_fd = secure_socket_get_connection_handle(svc_ctx->fd);
540                         if (client_fd < 0) {
541                                 ErrPrint("Failed to establish a new connection [%d]\n", svc_ctx->fd);
542                                 ret = -EFAULT;
543                                 break;
544                         }
545
546                         tcb = tcb_create(svc_ctx, client_fd);
547                         if (!tcb) {
548                                 ErrPrint("Failed to create a new TCB: %d (%d)\n", client_fd, svc_ctx->fd);
549                                 secure_socket_destroy_handle(client_fd);
550                         }
551                 } 
552
553                 if (FD_ISSET(svc_ctx->tcb_pipe[PIPE_READ], &set)) {
554                         if (read(svc_ctx->tcb_pipe[PIPE_READ], &tcb, sizeof(tcb)) != sizeof(tcb)) {
555                                 ErrPrint("Unable to read pipe: %s\n", strerror(errno));
556                                 ret = -EFAULT;
557                                 break;
558                         }
559
560                         if (!tcb) {
561                                 ErrPrint("Terminate service thread\n");
562                                 ret = -ECANCELED;
563                                 break;
564                         }
565
566                         /*!
567                          * \note
568                          * Invoke the service thread main, to notify the termination of a TCB
569                          */
570                         ret = svc_ctx->service_thread_main(tcb, NULL, svc_ctx->service_thread_data);
571
572                         /*!
573                          * at this time, the client thread can access this tcb.
574                          * how can I protect this TCB from deletion without disturbing the server thread?
575                          */
576                         tcb_destroy(svc_ctx, tcb);
577                 } 
578
579                 if (FD_ISSET(svc_ctx->evt_pipe[PIPE_READ], &set)) {
580                         if (read(svc_ctx->evt_pipe[PIPE_READ], &evt_ch, sizeof(evt_ch)) != sizeof(evt_ch)) {
581                                 ErrPrint("Unable to read pipe: %s\n", strerror(errno));
582                                 ret = -EFAULT;
583                                 break;
584                         }
585
586                         CRITICAL_SECTION_BEGIN(&svc_ctx->packet_list_lock);
587                         packet_info = eina_list_nth(svc_ctx->packet_list, 0);
588                         svc_ctx->packet_list = eina_list_remove(svc_ctx->packet_list, packet_info);
589                         CRITICAL_SECTION_END(&svc_ctx->packet_list_lock);
590
591                         if (packet_info) {
592                                 /*!
593                                  * \CRITICAL
594                                  * What happens if the client thread is terminated, so the packet_info->tcb is deleted
595                                  * while processing svc_ctx->service_thread_main?
596                                  */
597                                 ret = svc_ctx->service_thread_main(packet_info->tcb, packet_info->packet, svc_ctx->service_thread_data);
598                                 if (ret < 0)
599                                         ErrPrint("Service thread returns: %d\n", ret);
600
601                                 packet_destroy(packet_info->packet);
602                                 free(packet_info);
603                         }
604                 }
605
606                 processing_timer_event(svc_ctx, &set);
607                 /* If there is no such triggered FD? */
608         }
609
610         /*!
611          * Consuming all pended packets before terminates server thread.
612          *
613          * If the server thread is terminated, we should flush all pended packets.
614          * And we should services them.
615          * While processing this routine, the mutex is locked.
616          * So every other client thread will be slowed down, sequently, every clients can meet problems.
617          * But in case of termination of server thread, there could be systemetic problem.
618          * This only should be happenes while terminating the master daemon process.
619          */
620         CRITICAL_SECTION_BEGIN(&svc_ctx->packet_list_lock);
621         EINA_LIST_FREE(svc_ctx->packet_list, packet_info) {
622                 ret = read(svc_ctx->evt_pipe[PIPE_READ], &evt_ch, sizeof(evt_ch));
623                 DbgPrint("Flushing pipe: %d (%c)\n", ret, evt_ch);
624                 ret = svc_ctx->service_thread_main(packet_info->tcb, packet_info->packet, svc_ctx->service_thread_data);
625                 if (ret < 0)
626                         ErrPrint("Service thread returns: %d\n", ret);
627                 packet_destroy(packet_info->packet);
628                 free(packet_info);
629         }
630         CRITICAL_SECTION_END(&svc_ctx->packet_list_lock);
631
632         tcb_teminate_all(svc_ctx);
633         return (void *)ret;
634 }
635
636 /*!
637  * \NOTE
638  * MAIN THREAD
639  */
640 HAPI struct service_context *service_common_create(const char *addr, int (*service_thread_main)(struct tcb *tcb, struct packet *packet, void *data), void *data)
641 {
642         int status;
643         struct service_context *svc_ctx;
644
645         if (!service_thread_main || !addr) {
646                 ErrPrint("Invalid argument\n");
647                 return NULL;
648         }
649
650         if (unlink(addr) < 0)
651                 ErrPrint("[%s] - %s\n", addr, strerror(errno));
652
653         svc_ctx = calloc(1, sizeof(*svc_ctx));
654         if (!svc_ctx) {
655                 ErrPrint("Heap: %s\n", strerror(errno));
656                 return NULL;
657         }
658
659         svc_ctx->fd = secure_socket_create_server(addr);
660         if (svc_ctx->fd < 0) {
661                 free(svc_ctx);
662                 return NULL;
663         }
664
665         svc_ctx->service_thread_main = service_thread_main;
666         svc_ctx->service_thread_data = data;
667
668         if (fcntl(svc_ctx->fd, F_SETFD, FD_CLOEXEC) < 0)
669                 ErrPrint("fcntl: %s\n", strerror(errno));
670
671         if (fcntl(svc_ctx->fd, F_SETFL, O_NONBLOCK) < 0)
672                 ErrPrint("fcntl: %s\n", strerror(errno));
673
674         if (pipe2(svc_ctx->evt_pipe, O_NONBLOCK | O_CLOEXEC) < 0) {
675                 ErrPrint("pipe: %d\n", strerror(errno));
676                 secure_socket_destroy_handle(svc_ctx->fd);
677                 free(svc_ctx);
678                 return NULL;
679         }
680
681         if (pipe2(svc_ctx->tcb_pipe, O_NONBLOCK | O_CLOEXEC) < 0) {
682                 ErrPrint("pipe: %s\n", strerror(errno));
683                 CLOSE_PIPE(svc_ctx->evt_pipe);
684                 secure_socket_destroy_handle(svc_ctx->fd);
685                 free(svc_ctx);
686                 return NULL;
687         }
688
689         status = pthread_mutex_init(&svc_ctx->packet_list_lock, NULL);
690         if (status != 0) {
691                 ErrPrint("Unable to create a mutex: %s\n", strerror(status));
692                 CLOSE_PIPE(svc_ctx->evt_pipe);
693                 CLOSE_PIPE(svc_ctx->tcb_pipe);
694                 secure_socket_destroy_handle(svc_ctx->fd);
695                 free(svc_ctx);
696                 return NULL;
697         }
698
699         DbgPrint("Creating server thread\n");
700         status = pthread_create(&svc_ctx->server_thid, NULL, server_main, svc_ctx);
701         if (status != 0) {
702                 ErrPrint("Unable to create a thread for shortcut service: %s\n", strerror(status));
703                 status = pthread_mutex_destroy(&svc_ctx->packet_list_lock);
704                 if (status != 0)
705                         ErrPrint("Error: %s\n", strerror(status));
706                 CLOSE_PIPE(svc_ctx->evt_pipe);
707                 CLOSE_PIPE(svc_ctx->tcb_pipe);
708                 secure_socket_destroy_handle(svc_ctx->fd);
709                 free(svc_ctx);
710                 return NULL;
711         }
712
713         /*!
714          * \note
715          * To give a chance to run for server thread.
716          */
717         DbgPrint("Yield\n");
718         pthread_yield();
719
720         return svc_ctx;
721 }
722
723 /*!
724  * \note
725  * MAIN THREAD
726  */
727 HAPI int service_common_destroy(struct service_context *svc_ctx)
728 {
729         int status = 0;
730         void *ret;
731
732         if (!svc_ctx)
733                 return -EINVAL;
734
735         /*!
736          * \note
737          * Terminate server thread
738          */
739         if (write(svc_ctx->tcb_pipe[PIPE_WRITE], &status, sizeof(status)) != sizeof(status))
740                 ErrPrint("Failed to write: %s\n", strerror(errno));
741
742         status = pthread_join(svc_ctx->server_thid, &ret);
743         if (status != 0)
744                 ErrPrint("Join: %s\n", strerror(status));
745         else
746                 DbgPrint("Thread returns: %d\n", (int)ret);
747
748         secure_socket_destroy_handle(svc_ctx->fd);
749
750         status = pthread_mutex_destroy(&svc_ctx->packet_list_lock);
751         if (status != 0)
752                 ErrPrint("Unable to destroy a mutex: %s\n", strerror(status));
753
754         CLOSE_PIPE(svc_ctx->evt_pipe);
755         CLOSE_PIPE(svc_ctx->tcb_pipe);
756         free(svc_ctx);
757         return 0;
758 }
759
760 /*!
761  * \note
762  * SERVER THREAD
763  */
764 HAPI int tcb_fd(struct tcb *tcb)
765 {
766         if (!tcb)
767                 return -EINVAL;
768
769         return tcb->fd;
770 }
771
772 /*!
773  * \note
774  * SERVER THREAD
775  */
776 HAPI int tcb_client_type(struct tcb *tcb)
777 {
778         if (!tcb)
779                 return -EINVAL;
780
781         return tcb->type;
782 }
783
784 /*!
785  * \note
786  * SERVER THREAD
787  */
788 HAPI int tcb_client_type_set(struct tcb *tcb, enum tcb_type type)
789 {
790         if (!tcb)
791                 return -EINVAL;
792
793         DbgPrint("TCB[%p] Client type is changed to %d from %d\n", tcb, type, tcb->type);
794         tcb->type = type;
795         return 0;
796 }
797
798 /*!
799  * \note
800  * SERVER THREAD
801  */
802 HAPI struct service_context *tcb_svc_ctx(struct tcb *tcb)
803 {
804         if (!tcb)
805                 return NULL;
806
807         return tcb->svc_ctx;
808 }
809
810 /*!
811  * \note
812  * SERVER THREAD
813  */
814 HAPI int service_common_unicast_packet(struct tcb *tcb, struct packet *packet)
815 {
816         struct service_context *svc_ctx;
817         if (!tcb || !packet) {
818                 DbgPrint("Invalid unicast: tcb[%p], packet[%p]\n", tcb, packet);
819                 return -EINVAL;
820         }
821
822         svc_ctx = tcb->svc_ctx;
823
824         DbgPrint("Unicast packet\n");
825         return secure_socket_send(tcb->fd, (void *)packet_data(packet), packet_size(packet));
826 }
827
828 /*!
829  * \note
830  * SERVER THREAD
831  */
832 HAPI int service_common_multicast_packet(struct tcb *tcb, struct packet *packet, int type)
833 {
834         Eina_List *l;
835         struct tcb *target;
836         struct service_context *svc_ctx;
837         int ret;
838
839         if (!tcb || !packet) {
840                 DbgPrint("Invalid multicast: tcb[%p], packet[%p]\n", tcb, packet);
841                 return -EINVAL;
842         }
843
844         svc_ctx = tcb->svc_ctx;
845
846         DbgPrint("Multicasting packets\n");
847         EINA_LIST_FOREACH(svc_ctx->tcb_list, l, target) {
848                 if (target == tcb || target->type != type) {
849                         DbgPrint("Skip target: %p(%d) == %p/%d\n", target, target->type, tcb, type);
850                         continue;
851                 }
852
853                 ret = secure_socket_send(target->fd, (void *)packet_data(packet), packet_size(packet));
854                 if (ret < 0)
855                         ErrPrint("Failed to send packet: %d\n", ret);
856         }
857         DbgPrint("Finish to multicast packet\n");
858         return 0;
859 }
860
861 /*!
862  * \note
863  * SERVER THREAD
864  */
865 HAPI struct service_event_item *service_common_add_timer(struct service_context *svc_ctx, double timer, int (*timer_cb)(struct service_context *svc_cx, void *data), void *data)
866 {
867         struct service_event_item *item;
868         struct itimerspec spec;
869
870         item = calloc(1, sizeof(*item));
871         if (!item) {
872                 ErrPrint("Heap: %s\n", strerror(errno));
873                 return NULL;
874         }
875
876         item->type = SERVICE_EVENT_TIMER;
877         item->info.timer.fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
878         if (item->info.timer.fd < 0) {
879                 ErrPrint("Error: %s\n", strerror(errno));
880                 free(item);
881                 return NULL;
882         }
883
884         spec.it_interval.tv_sec = (time_t)timer;
885         spec.it_interval.tv_nsec = (timer - spec.it_interval.tv_sec) * 1000000000;
886         spec.it_value.tv_sec = 0;
887         spec.it_value.tv_nsec = 0;
888
889         if (timerfd_settime(item->info.timer.fd, 0, &spec, NULL) < 0) {
890                 ErrPrint("Error: %s\n", strerror(errno));
891                 if (close(item->info.timer.fd) < 0)
892                         ErrPrint("close: %s\n", strerror(errno));
893                 free(item);
894                 return NULL;
895         }
896
897         item->event_cb = timer_cb;
898         item->cbdata = data;
899
900         svc_ctx->event_list = eina_list_append(svc_ctx->event_list, item);
901         return item;
902 }
903
904 /*!
905  * \note
906  * SERVER THREAD
907  */
908 HAPI int service_common_del_timer(struct service_context *svc_ctx, struct service_event_item *item)
909 {
910         if (!eina_list_data_find(svc_ctx->event_list, item)) {
911                 ErrPrint("Invalid event item\n");
912                 return -EINVAL;
913         }
914
915         svc_ctx->event_list = eina_list_remove(svc_ctx->event_list, item);
916
917         if (close(item->info.timer.fd) < 0)
918                 ErrPrint("close: %s\n", strerror(errno));
919         free(item);
920         return 0;
921 }
922
923 HAPI int service_common_fd(struct service_context *ctx)
924 {
925         return ctx->fd;
926 }
927
928 /* End of a file */