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