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