Various patches are applied
[platform/framework/web/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 <unistd.h>
25 #include <fcntl.h>
26
27 #include <dlog.h>
28 #include <Eina.h>
29
30 #include "service_common.h"
31 #include "util.h"
32 #include "debug.h"
33 #include "conf.h"
34
35 #define EVT_CH          'e'
36 #define EVT_END_CH      'x'
37
38 int errno;
39
40 /*!
41  * \note
42  * Server information and global (only in this file-scope) variables are defined
43  */
44
45 struct service_context {
46         pthread_t server_thid; /*!< Server thread Id */
47         int fd; /*!< Server socket handle */
48
49         Eina_List *tcb_list; /*!< TCB list, list of every thread for client connections */
50
51         Eina_List *packet_list;
52         pthread_mutex_t packet_list_lock;
53         int evt_pipe[PIPE_MAX];
54         int tcb_pipe[PIPE_MAX];
55
56         int (*service_thread_main)(struct tcb *tcb, struct packet *packet, void *data);
57         void *service_thread_data;
58 };
59
60 struct packet_info {
61         struct tcb *tcb;
62         struct packet *packet;
63 };
64
65 /*!
66  * \note
67  * Thread Control Block
68  * - The main server will create a thread for every client connections.
69  *   When a new client is comming to us, this TCB block will be allocated and initialized.
70  */
71 struct tcb { /* Thread controll block */
72         struct service_context *svc_ctx;
73         pthread_t thid; /*!< Thread Id */
74         int fd; /*!< Connection handle */
75         enum tcb_type type;
76 };
77
78 /*!
79  * Do services for clients
80  * Routing packets to destination processes.
81  * CLIENT THREAD
82  */
83 static void *client_packet_pump_main(void *data)
84 {
85         struct tcb *tcb = data;
86         struct service_context *svc_ctx = tcb->svc_ctx;
87         struct packet *packet;
88         fd_set set;
89         char *ptr;
90         int size;
91         int packet_offset;
92         int recv_offset;
93         int pid;
94         int ret;
95         char evt_ch = EVT_CH;
96         enum {
97                 RECV_INIT,
98                 RECV_HEADER,
99                 RECV_PAYLOAD,
100                 RECV_DONE,
101         } recv_state;
102         struct packet_info *packet_info;
103         Eina_List *l;
104
105         ret = 0;
106         recv_state = RECV_INIT;
107         DbgPrint("Socket data pumping thread is activated\n");
108         /*!
109          * \note
110          * To escape from the switch statement, we use this ret value
111          */
112         while (ret == 0) {
113                 FD_ZERO(&set);
114                 FD_SET(tcb->fd, &set);
115                 ret = select(tcb->fd + 1, &set, NULL, NULL, NULL);
116                 if (ret < 0) {
117                         ret = -errno;
118                         if (errno == EINTR) {
119                                 DbgPrint("INTERRUPTED\n");
120                                 ret = 0;
121                                 continue;
122                         }
123                         ErrPrint("Error: %s\n", strerror(errno));
124                         free(ptr);
125                         ptr = NULL;
126                         break;
127                 } else if (ret == 0) {
128                         ErrPrint("Timeout\n");
129                         ret = -ETIMEDOUT;
130                         free(ptr);
131                         ptr = NULL;
132                         break;
133                 }
134
135                 if (!FD_ISSET(tcb->fd, &set)) {
136                         ErrPrint("Unexpected handler is toggled\n");
137                         ret = -EINVAL;
138                         free(ptr);
139                         ptr = NULL;
140                         break;
141                 }
142                 
143                 /*!
144                  * \TODO
145                  * Service!!! Receive packet & route packet
146                  */
147                 switch (recv_state) {
148                 case RECV_INIT:
149                         size = packet_header_size();
150                         packet_offset = 0;
151                         recv_offset = 0;
152                         packet = NULL;
153                         ptr = malloc(size);
154                         if (!ptr) {
155                                 ErrPrint("Heap: %s\n", strerror(errno));
156                                 ret = -ENOMEM;
157                                 break;
158                         }
159                         recv_state = RECV_HEADER;
160                         /* Go through, don't break from here */
161                 case RECV_HEADER:
162                         ret = secure_socket_recv(tcb->fd, ptr, size - recv_offset, &pid);
163                         if (ret <= 0) {
164                                 if (ret == 0)
165                                         ret = -ECANCELED;
166                                 free(ptr);
167                                 ptr = NULL;
168                                 break;
169                         }
170
171                         recv_offset += ret;
172                         ret = 0;
173
174                         if (recv_offset == size) {
175                                 packet = packet_build(packet, packet_offset, ptr, size);
176                                 free(ptr);
177                                 ptr = NULL;
178                                 if (!packet) {
179                                         ret = -EFAULT;
180                                         break;
181                                 }
182
183                                 packet_offset += recv_offset;
184
185                                 size = packet_payload_size(packet);
186                                 if (size <= 0) {
187                                         recv_state = RECV_DONE;
188                                         recv_offset = 0;
189                                         break;
190                                 }
191
192                                 recv_state = RECV_PAYLOAD;
193                                 recv_offset = 0;
194
195                                 ptr = malloc(size);
196                                 if (!ptr) {
197                                         ErrPrint("Heap: %s\n", strerror(errno));
198                                         ret = -ENOMEM;
199                                 }
200                         }
201                         break;
202                 case RECV_PAYLOAD:
203                         ret = secure_socket_recv(tcb->fd, ptr, size - recv_offset, &pid);
204                         if (ret <= 0) {
205                                 if (ret == 0)
206                                         ret = -ECANCELED;
207                                 free(ptr);
208                                 ptr = NULL;
209                                 break;
210                         }
211
212                         recv_offset += ret;
213                         ret = 0;
214
215                         if (recv_offset == size) {
216                                 packet = packet_build(packet, packet_offset, ptr, size);
217                                 free(ptr);
218                                 ptr = NULL;
219                                 if (!packet) {
220                                         ret = -EFAULT;
221                                         break;
222                                 }
223
224                                 packet_offset += recv_offset;
225
226                                 recv_state = RECV_DONE;
227                                 recv_offset = 0;
228                         }
229                         break;
230                 case RECV_DONE:
231                 default:
232                         /* Dead code */
233                         break;
234                 }
235
236                 if (recv_state == RECV_DONE) {
237                         /*!
238                          * Push this packet to the packet list with TCB
239                          * Then the service main function will get this.
240                          */
241                         packet_info = malloc(sizeof(*packet_info));
242                         if (!packet_info) {
243                                 ret = -errno;
244                                 ErrPrint("Heap: %s\n", strerror(errno));
245                                 packet_destroy(packet);
246                                 break;
247                         }
248
249                         packet_info->packet = packet;
250                         packet_info->tcb = tcb;
251
252                         DbgPrint("New packet is built\n");
253                         CRITICAL_SECTION_BEGIN(&svc_ctx->packet_list_lock);
254                         svc_ctx->packet_list = eina_list_append(svc_ctx->packet_list, packet_info);
255                         CRITICAL_SECTION_END(&svc_ctx->packet_list_lock);
256
257                         if (write(svc_ctx->evt_pipe[PIPE_WRITE], &evt_ch, sizeof(evt_ch)) != sizeof(evt_ch)) {
258                                 ret = -errno;
259                                 ErrPrint("Unable to write a pipe: %s\n", strerror(errno));
260                                 CRITICAL_SECTION_BEGIN(&svc_ctx->packet_list_lock);
261                                 svc_ctx->packet_list = eina_list_remove(svc_ctx->packet_list, packet_info);
262                                 CRITICAL_SECTION_END(&svc_ctx->packet_list_lock);
263
264                                 packet_destroy(packet);
265                                 free(packet_info);
266                                 ErrPrint("Terminate thread: %p\n", tcb);
267                                 break;
268                         } else {
269                                 DbgPrint("Packet received: %d bytes\n", packet_offset);
270                                 recv_state = RECV_INIT;
271                         }
272                 }
273         }
274
275         CRITICAL_SECTION_BEGIN(&svc_ctx->packet_list_lock);
276         EINA_LIST_FOREACH(svc_ctx->packet_list, l, packet_info) {
277                 if (packet_info->tcb == tcb) {
278                         DbgPrint("Reset ptr of the TCB[%p] in the list of packet info\n", tcb);
279                         packet_info->tcb = NULL;
280                 }
281         }
282         CRITICAL_SECTION_END(&svc_ctx->packet_list_lock);
283
284         /*!
285          * \note
286          * Emit a signal to collect this TCB from the SERVER THREAD.
287          */
288         DbgPrint("Emit a signal to destroy TCB[%p]\n", tcb);
289         if (write(svc_ctx->tcb_pipe[PIPE_WRITE], &tcb, sizeof(tcb)) != sizeof(tcb))
290                 ErrPrint("Unable to write pipe: %s\n", strerror(errno));
291
292         return (void *)ret;
293 }
294
295 /*!
296  * \note
297  * SERVER THREAD
298  */
299 static inline struct tcb *tcb_create(struct service_context *svc_ctx, int fd)
300 {
301         struct tcb *tcb;
302         int status;
303
304         tcb = malloc(sizeof(*tcb));
305         if (!tcb) {
306                 ErrPrint("Heap: %s\n", strerror(errno));
307                 return NULL;
308         }
309
310         tcb->fd = fd;
311         tcb->svc_ctx = svc_ctx;
312         tcb->type = TCB_CLIENT_TYPE_APP;
313
314         DbgPrint("Create a new service thread [%d]\n", fd);
315         status = pthread_create(&tcb->thid, NULL, client_packet_pump_main, tcb);
316         if (status != 0) {
317                 ErrPrint("Unable to create a new thread: %s\n", strerror(status));
318                 free(tcb);
319                 return NULL;
320         }
321
322         svc_ctx->tcb_list = eina_list_append(svc_ctx->tcb_list, tcb);
323         return tcb;
324 }
325
326 /*!
327  * \note
328  * SERVER THREAD
329  */
330 static inline void tcb_teminate_all(struct service_context *svc_ctx)
331 {
332         struct tcb *tcb;
333         void *ret;
334         int status;
335
336         /*!
337          * We don't need to make critical section on here.
338          * If we call this after terminate the server thread first.
339          * Then there is no other thread to access tcb_list.
340          */
341         EINA_LIST_FREE(svc_ctx->tcb_list, tcb) {
342                 /*!
343                  * ASSERT(tcb->fd >= 0);
344                  */
345                 secure_socket_destroy_handle(tcb->fd);
346
347                 status = pthread_join(tcb->thid, &ret);
348                 if (status != 0)
349                         ErrPrint("Unable to join a thread: %s\n", strerror(status));
350                 else
351                         DbgPrint("Thread returns: %d\n", (int)ret);
352
353                 free(tcb);
354         }
355 }
356
357 /*!
358  * \note
359  * SERVER THREAD
360  */
361 static inline void tcb_destroy(struct service_context *svc_ctx, struct tcb *tcb)
362 {
363         void *ret;
364         int status;
365
366         svc_ctx->tcb_list = eina_list_remove(svc_ctx->tcb_list, tcb);
367         /*!
368          * ASSERT(tcb->fd >= 0);
369          * Close the connection, and then collecting the return value of thread
370          */
371         secure_socket_destroy_handle(tcb->fd);
372
373         status = pthread_join(tcb->thid, &ret);
374         if (status != 0)
375                 ErrPrint("Unable to join a thread: %s\n", strerror(status));
376         else
377                 DbgPrint("Thread returns: %d\n", (int)ret);
378
379         free(tcb);
380 }
381
382 /*!
383  * Accept new client connections
384  * And create a new thread for service.
385  *
386  * Create Client threads & Destroying them
387  * SERVER THREAD
388  */
389 static void *server_main(void *data)
390 {
391         struct service_context *svc_ctx = data;
392         fd_set set;
393         int ret;
394         int client_fd;
395         struct tcb *tcb;
396         int fd;
397         char evt_ch;
398         struct packet_info *packet_info;
399
400         DbgPrint("Server thread is activated\n");
401         fd = svc_ctx->fd > svc_ctx->tcb_pipe[PIPE_READ] ? svc_ctx->fd : svc_ctx->tcb_pipe[PIPE_READ];
402         fd = fd > svc_ctx->evt_pipe[PIPE_READ] ? fd : svc_ctx->evt_pipe[PIPE_READ];
403         fd += 1;
404
405         while (1) {
406                 FD_ZERO(&set);
407                 FD_SET(svc_ctx->fd, &set);
408                 FD_SET(svc_ctx->tcb_pipe[PIPE_READ], &set);
409                 FD_SET(svc_ctx->evt_pipe[PIPE_READ], &set);
410
411                 ret = select(fd, &set, NULL, NULL, NULL);
412                 if (ret < 0) {
413                         ret = -errno;
414                         if (errno == EINTR) {
415                                 DbgPrint("INTERRUPTED\n");
416                                 continue;
417                         }
418                         ErrPrint("Error: %s\n", strerror(errno));
419                         break;
420                 } else if (ret == 0) {
421                         ErrPrint("Timeout\n");
422                         ret = -ETIMEDOUT;
423                         break;
424                 }
425
426                 if (FD_ISSET(svc_ctx->fd, &set)) {
427                         client_fd = secure_socket_get_connection_handle(svc_ctx->fd);
428                         DbgPrint("New client connection arrived (%d)\n", client_fd);
429                         if (client_fd < 0) {
430                                 ErrPrint("Failed to establish the client connection\n");
431                                 ret = -EFAULT;
432                                 break;
433                         }
434
435                         tcb = tcb_create(svc_ctx, client_fd);
436                         if (!tcb)
437                                 secure_socket_destroy_handle(client_fd);
438                         else
439                                 DbgPrint("Creating TCB[%p]\n", tcb);
440                 } 
441
442                 if (FD_ISSET(svc_ctx->tcb_pipe[PIPE_READ], &set)) {
443                         if (read(svc_ctx->tcb_pipe[PIPE_READ], &tcb, sizeof(tcb)) != sizeof(tcb)) {
444                                 ErrPrint("Unable to read pipe: %s\n", strerror(errno));
445                                 ret = -EFAULT;
446                                 break;
447                         }
448
449                         DbgPrint("Destroying TCB[%p]\n", tcb);
450                         /*!
451                          * at this time, the client thread can access this tcb.
452                          * how can I protect this TCB from deletion without disturbing the server thread?
453                          */
454                         tcb_destroy(svc_ctx, tcb);
455                 } 
456
457                 if (FD_ISSET(svc_ctx->evt_pipe[PIPE_READ], &set)) {
458                         if (read(svc_ctx->evt_pipe[PIPE_READ], &evt_ch, sizeof(evt_ch)) != sizeof(evt_ch)) {
459                                 ErrPrint("Unable to read pipe: %s\n", strerror(errno));
460                                 ret = -EFAULT;
461                                 break;
462                         }
463
464                         DbgPrint("Event CH: %c\n", evt_ch);
465
466                         CRITICAL_SECTION_BEGIN(&svc_ctx->packet_list_lock);
467                         packet_info = eina_list_nth(svc_ctx->packet_list, 0);
468                         svc_ctx->packet_list = eina_list_remove(svc_ctx->packet_list, packet_info);
469                         CRITICAL_SECTION_END(&svc_ctx->packet_list_lock);
470
471                         /*!
472                          * \CRITICAL
473                          * What happens if the client thread is terminated, so the packet_info->tcb is deleted
474                          * while processing svc_ctx->service_thread_main?
475                          */
476                         ret = svc_ctx->service_thread_main(packet_info->tcb, packet_info->packet, svc_ctx->service_thread_data);
477                         if (ret < 0)
478                                 ErrPrint("Service thread returns: %d\n", ret);
479
480                         packet_destroy(packet_info->packet);
481                         free(packet_info);
482                 }
483
484                 /* If there is no such triggered FD? */
485         }
486
487         /*!
488          * Consuming all pended packets before terminates server thread.
489          *
490          * If the server thread is terminated, we should flush all pended packets.
491          * And we should services them.
492          * While processing this routine, the mutex is locked.
493          * So every other client thread will be slowed down, sequently, every clients can meet problems.
494          * But in case of termination of server thread, there could be systemetic problem.
495          * This only should be happenes while terminating the master daemon process.
496          */
497         CRITICAL_SECTION_BEGIN(&svc_ctx->packet_list_lock);
498         EINA_LIST_FREE(svc_ctx->packet_list, packet_info) {
499                 ret = read(svc_ctx->evt_pipe[PIPE_READ], &evt_ch, sizeof(evt_ch));
500                 DbgPrint("Flushing pipe: %d (%c)\n", ret, evt_ch);
501                 ret = svc_ctx->service_thread_main(packet_info->tcb, packet_info->packet, svc_ctx->service_thread_data);
502                 if (ret < 0)
503                         ErrPrint("Service thread returns: %d\n", ret);
504                 packet_destroy(packet_info->packet);
505                 free(packet_info);
506         }
507         CRITICAL_SECTION_END(&svc_ctx->packet_list_lock);
508
509         tcb_teminate_all(svc_ctx);
510         return (void *)ret;
511 }
512
513 /*!
514  * \NOTE
515  * MAIN THREAD
516  */
517 HAPI struct service_context *service_common_create(const char *addr, int (*service_thread_main)(struct tcb *tcb, struct packet *packet, void *data), void *data)
518 {
519         int status;
520         struct service_context *svc_ctx;
521
522         if (!service_thread_main || !addr) {
523                 ErrPrint("Invalid argument\n");
524                 return NULL;
525         }
526
527         if (unlink(addr) < 0)
528                 ErrPrint("[%s] - %s\n", addr, strerror(errno));
529
530         svc_ctx = calloc(1, sizeof(*svc_ctx));
531         if (!svc_ctx) {
532                 ErrPrint("Heap: %s\n", strerror(errno));
533                 return NULL;
534         }
535
536         svc_ctx->fd = secure_socket_create_server(addr);
537         if (svc_ctx->fd < 0) {
538                 free(svc_ctx);
539                 return NULL;
540         }
541
542         svc_ctx->service_thread_main = service_thread_main;
543         svc_ctx->service_thread_data = data;
544
545         if (fcntl(svc_ctx->fd, F_SETFD, FD_CLOEXEC) < 0)
546                 ErrPrint("fcntl: %s\n", strerror(errno));
547
548         if (fcntl(svc_ctx->fd, F_SETFL, O_NONBLOCK) < 0)
549                 ErrPrint("fcntl: %s\n", strerror(errno));
550
551         if (pipe2(svc_ctx->evt_pipe, O_NONBLOCK | O_CLOEXEC) < 0) {
552                 ErrPrint("pipe: %d\n", strerror(errno));
553                 secure_socket_destroy_handle(svc_ctx->fd);
554                 free(svc_ctx);
555                 return NULL;
556         }
557
558         if (pipe2(svc_ctx->tcb_pipe, O_NONBLOCK | O_CLOEXEC) < 0) {
559                 ErrPrint("pipe: %s\n", strerror(errno));
560                 CLOSE_PIPE(svc_ctx->evt_pipe);
561                 secure_socket_destroy_handle(svc_ctx->fd);
562                 free(svc_ctx);
563                 return NULL;
564         }
565
566         status = pthread_mutex_init(&svc_ctx->packet_list_lock, NULL);
567         if (status != 0) {
568                 ErrPrint("Unable to create a mutex: %s\n", strerror(status));
569                 CLOSE_PIPE(svc_ctx->evt_pipe);
570                 CLOSE_PIPE(svc_ctx->tcb_pipe);
571                 secure_socket_destroy_handle(svc_ctx->fd);
572                 free(svc_ctx);
573                 return NULL;
574         }
575
576         DbgPrint("Creating server thread\n");
577         status = pthread_create(&svc_ctx->server_thid, NULL, server_main, svc_ctx);
578         if (status != 0) {
579                 ErrPrint("Unable to create a thread for shortcut service: %s\n", strerror(status));
580                 status = pthread_mutex_destroy(&svc_ctx->packet_list_lock);
581                 if (status != 0)
582                         ErrPrint("Error: %s\n", strerror(status));
583                 CLOSE_PIPE(svc_ctx->evt_pipe);
584                 CLOSE_PIPE(svc_ctx->tcb_pipe);
585                 secure_socket_destroy_handle(svc_ctx->fd);
586                 free(svc_ctx);
587                 return NULL;
588         }
589
590         return svc_ctx;
591 }
592
593 /*!
594  * \note
595  * MAIN THREAD
596  */
597 HAPI int service_common_destroy(struct service_context *svc_ctx)
598 {
599         int status;
600         void *ret;
601
602         if (!svc_ctx)
603                 return -EINVAL;
604
605         /*!
606          * \note
607          * Terminate server thread
608          */
609         secure_socket_destroy_handle(svc_ctx->fd);
610
611         status = pthread_join(svc_ctx->server_thid, &ret);
612         if (status != 0)
613                 ErrPrint("Join: %s\n", strerror(status));
614         else
615                 DbgPrint("Thread returns: %d\n", (int)ret);
616
617         status = pthread_mutex_destroy(&svc_ctx->packet_list_lock);
618         if (status != 0)
619                 ErrPrint("Unable to destroy a mutex: %s\n", strerror(status));
620
621         CLOSE_PIPE(svc_ctx->evt_pipe);
622         CLOSE_PIPE(svc_ctx->tcb_pipe);
623         free(svc_ctx);
624         return 0;
625 }
626
627 /*!
628  * \note
629  * SERVER THREAD
630  */
631 HAPI int tcb_fd(struct tcb *tcb)
632 {
633         if (!tcb)
634                 return -EINVAL;
635
636         return tcb->fd;
637 }
638
639 /*!
640  * \note
641  * SERVER THREAD
642  */
643 HAPI int tcb_client_type(struct tcb *tcb)
644 {
645         if (!tcb)
646                 return -EINVAL;
647
648         return tcb->type;
649 }
650
651 /*!
652  * \note
653  * SERVER THREAD
654  */
655 HAPI int tcb_client_type_set(struct tcb *tcb, enum tcb_type type)
656 {
657         if (!tcb)
658                 return -EINVAL;
659
660         DbgPrint("TCB[%p] Client type is changed to %d from %d\n", tcb, type, tcb->type);
661         tcb->type = type;
662         return 0;
663 }
664
665 /*!
666  * \note
667  * SERVER THREAD
668  */
669 HAPI struct service_context *tcb_svc_ctx(struct tcb *tcb)
670 {
671         if (!tcb)
672                 return NULL;
673
674         return tcb->svc_ctx;
675 }
676
677 /*!
678  * \note
679  * SERVER THREAD
680  */
681 HAPI int service_common_unicast_packet(struct tcb *tcb, struct packet *packet)
682 {
683         struct service_context *svc_ctx;
684         if (!tcb || !packet)
685                 return -EINVAL;
686
687         svc_ctx = tcb->svc_ctx;
688
689         DbgPrint("Unicast packet\n");
690         return secure_socket_send(tcb->fd, (void *)packet_data(packet), packet_size(packet));
691 }
692
693 /*!
694  * \note
695  * SERVER THREAD
696  */
697 HAPI int service_common_multicast_packet(struct tcb *tcb, struct packet *packet, int type)
698 {
699         Eina_List *l;
700         struct tcb *target;
701         struct service_context *svc_ctx;
702         int ret;
703
704         if (!tcb || !packet)
705                 return -EINVAL;
706
707         svc_ctx = tcb->svc_ctx;
708
709         DbgPrint("Multicasting packets\n");
710         EINA_LIST_FOREACH(svc_ctx->tcb_list, l, target) {
711                 if (target == tcb || target->type != type) {
712                         DbgPrint("Skip target: %p(%d) == %p/%d\n", target, target->type, tcb, type);
713                         continue;
714                 }
715
716                 ret = secure_socket_send(target->fd, (void *)packet_data(packet), packet_size(packet));
717                 if (ret < 0)
718                         ErrPrint("Failed to send packet: %d\n", ret);
719         }
720         DbgPrint("Finish to multicast packet\n");
721         return 0;
722 }
723
724 /* End of a file */