2 * Copyright 2013 Samsung Electronics Co., Ltd
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
8 * http://floralicense.org/license/
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.
19 #include <secure_socket.h>
23 #include <sys/types.h>
24 #include <sys/timerfd.h>
31 #include "service_common.h"
37 #define EVT_END_CH 'x'
41 struct service_event_item {
52 int (*event_cb)(struct service_context *svc_cx, void *data);
58 * Server information and global (only in this file-scope) variables are defined
60 struct service_context {
61 pthread_t server_thid; /*!< Server thread Id */
62 int fd; /*!< Server socket handle */
64 Eina_List *tcb_list; /*!< TCB list, list of every thread for client connections */
66 Eina_List *packet_list;
67 pthread_mutex_t packet_list_lock;
68 int evt_pipe[PIPE_MAX];
69 int tcb_pipe[PIPE_MAX];
71 int (*service_thread_main)(struct tcb *tcb, struct packet *packet, void *data);
72 void *service_thread_data;
74 Eina_List *event_list;
79 struct packet *packet;
84 * Thread Control Block
85 * - The main server will create a thread for every client connections.
86 * When a new client is comming to us, this TCB block will be allocated and initialized.
88 struct tcb { /* Thread controll block */
89 struct service_context *svc_ctx;
90 pthread_t thid; /*!< Thread Id */
91 int fd; /*!< Connection handle */
93 int ctrl_pipe[PIPE_MAX];
97 * Do services for clients
98 * Routing packets to destination processes.
101 static void *client_packet_pump_main(void *data)
103 struct tcb *tcb = data;
104 struct service_context *svc_ctx = tcb->svc_ctx;
105 struct packet *packet;
114 char evt_ch = EVT_CH;
121 struct packet_info *packet_info;
125 recv_state = RECV_INIT;
128 * To escape from the switch statement, we use this ret value
132 FD_SET(tcb->fd, &set);
133 FD_SET(tcb->ctrl_pipe[PIPE_READ], &set);
134 fd = tcb->fd > tcb->ctrl_pipe[PIPE_READ] ? tcb->fd : tcb->ctrl_pipe[PIPE_READ];
135 ret = select(fd + 1, &set, NULL, NULL, NULL);
138 if (errno == EINTR) {
139 DbgPrint("INTERRUPTED\n");
143 ErrPrint("Error: %s\n", strerror(errno));
147 } else if (ret == 0) {
148 ErrPrint("Timeout\n");
155 if (FD_ISSET(tcb->ctrl_pipe[PIPE_READ], &set)) {
156 DbgPrint("Thread is canceled\n");
163 if (!FD_ISSET(tcb->fd, &set)) {
164 ErrPrint("Unexpected handler is toggled\n");
173 * Service!!! Receive packet & route packet
175 switch (recv_state) {
177 size = packet_header_size();
183 ErrPrint("Heap: %s\n", strerror(errno));
187 recv_state = RECV_HEADER;
188 /* Go through, don't break from here */
190 ret = secure_socket_recv(tcb->fd, ptr, size - recv_offset, &pid);
202 if (recv_offset == size) {
203 packet = packet_build(packet, packet_offset, ptr, size);
211 packet_offset += recv_offset;
213 size = packet_payload_size(packet);
215 recv_state = RECV_DONE;
220 recv_state = RECV_PAYLOAD;
225 ErrPrint("Heap: %s\n", strerror(errno));
231 ret = secure_socket_recv(tcb->fd, ptr, size - recv_offset, &pid);
243 if (recv_offset == size) {
244 packet = packet_build(packet, packet_offset, ptr, size);
252 packet_offset += recv_offset;
254 recv_state = RECV_DONE;
264 if (recv_state == RECV_DONE) {
266 * Push this packet to the packet list with TCB
267 * Then the service main function will get this.
269 packet_info = malloc(sizeof(*packet_info));
272 ErrPrint("Heap: %s\n", strerror(errno));
273 packet_destroy(packet);
277 packet_info->packet = packet;
278 packet_info->tcb = tcb;
280 CRITICAL_SECTION_BEGIN(&svc_ctx->packet_list_lock);
281 svc_ctx->packet_list = eina_list_append(svc_ctx->packet_list, packet_info);
282 CRITICAL_SECTION_END(&svc_ctx->packet_list_lock);
284 if (write(svc_ctx->evt_pipe[PIPE_WRITE], &evt_ch, sizeof(evt_ch)) != sizeof(evt_ch)) {
286 ErrPrint("Unable to write a pipe: %s\n", strerror(errno));
287 CRITICAL_SECTION_BEGIN(&svc_ctx->packet_list_lock);
288 svc_ctx->packet_list = eina_list_remove(svc_ctx->packet_list, packet_info);
289 CRITICAL_SECTION_END(&svc_ctx->packet_list_lock);
291 packet_destroy(packet);
293 ErrPrint("Terminate thread: %p\n", tcb);
296 DbgPrint("Packet received: %d bytes\n", packet_offset);
297 recv_state = RECV_INIT;
302 CRITICAL_SECTION_BEGIN(&svc_ctx->packet_list_lock);
303 EINA_LIST_FOREACH(svc_ctx->packet_list, l, packet_info) {
304 if (packet_info->tcb == tcb) {
305 DbgPrint("Reset ptr of the TCB[%p] in the list of packet info\n", tcb);
306 packet_info->tcb = NULL;
309 CRITICAL_SECTION_END(&svc_ctx->packet_list_lock);
313 * Emit a signal to collect this TCB from the SERVER THREAD.
315 if (write(svc_ctx->tcb_pipe[PIPE_WRITE], &tcb, sizeof(tcb)) != sizeof(tcb))
316 ErrPrint("Unable to write pipe: %s\n", strerror(errno));
325 static inline struct tcb *tcb_create(struct service_context *svc_ctx, int fd)
330 tcb = malloc(sizeof(*tcb));
332 ErrPrint("Heap: %s\n", strerror(errno));
336 if (pipe2(tcb->ctrl_pipe, O_NONBLOCK | O_CLOEXEC) < 0) {
337 ErrPrint("pipe2: %s\n", strerror(errno));
343 tcb->svc_ctx = svc_ctx;
344 tcb->type = TCB_CLIENT_TYPE_APP;
346 DbgPrint("Create a new service thread [%d]\n", fd);
347 status = pthread_create(&tcb->thid, NULL, client_packet_pump_main, tcb);
349 ErrPrint("Unable to create a new thread: %s\n", strerror(status));
350 CLOSE_PIPE(tcb->ctrl_pipe);
355 svc_ctx->tcb_list = eina_list_append(svc_ctx->tcb_list, tcb);
363 static inline void tcb_teminate_all(struct service_context *svc_ctx)
368 char ch = EVT_END_CH;
371 * We don't need to make critical section on here.
372 * If we call this after terminate the server thread first.
373 * Then there is no other thread to access tcb_list.
375 EINA_LIST_FREE(svc_ctx->tcb_list, tcb) {
377 * ASSERT(tcb->fd >= 0);
379 if (write(tcb->ctrl_pipe[PIPE_WRITE], &ch, sizeof(ch)) != sizeof(ch))
380 ErrPrint("write: %s\n", strerror(errno));
382 status = pthread_join(tcb->thid, &ret);
384 ErrPrint("Unable to join a thread: %s\n", strerror(status));
386 DbgPrint("Thread returns: %d\n", (int)ret);
388 secure_socket_destroy_handle(tcb->fd);
390 CLOSE_PIPE(tcb->ctrl_pipe);
399 static inline void tcb_destroy(struct service_context *svc_ctx, struct tcb *tcb)
403 char ch = EVT_END_CH;
405 svc_ctx->tcb_list = eina_list_remove(svc_ctx->tcb_list, tcb);
407 * ASSERT(tcb->fd >= 0);
408 * Close the connection, and then collecting the return value of thread
410 if (write(tcb->ctrl_pipe[PIPE_WRITE], &ch, sizeof(ch)) != sizeof(ch))
411 ErrPrint("write: %s\n", strerror(errno));
413 status = pthread_join(tcb->thid, &ret);
415 ErrPrint("Unable to join a thread: %s\n", strerror(status));
417 DbgPrint("Thread returns: %d\n", (int)ret);
419 secure_socket_destroy_handle(tcb->fd);
421 CLOSE_PIPE(tcb->ctrl_pipe);
429 static inline int update_fdset(struct service_context *svc_ctx, fd_set *set)
432 struct service_event_item *item;
437 FD_SET(svc_ctx->fd, set);
440 FD_SET(svc_ctx->tcb_pipe[PIPE_READ], set);
441 if (svc_ctx->tcb_pipe[PIPE_READ] > fd)
442 fd = svc_ctx->tcb_pipe[PIPE_READ];
444 FD_SET(svc_ctx->evt_pipe[PIPE_READ], set);
445 if (svc_ctx->evt_pipe[PIPE_READ] > fd)
446 fd = svc_ctx->evt_pipe[PIPE_READ];
448 EINA_LIST_FOREACH(svc_ctx->event_list, l, item) {
449 if (item->type == SERVICE_EVENT_TIMER) {
450 FD_SET(item->info.timer.fd, set);
451 if (fd < item->info.timer.fd)
452 fd = item->info.timer.fd;
463 static inline void processing_timer_event(struct service_context *svc_ctx, fd_set *set)
465 uint64_t expired_count;
468 struct service_event_item *item;
470 EINA_LIST_FOREACH_SAFE(svc_ctx->event_list, l, n, item) {
471 switch (item->type) {
472 case SERVICE_EVENT_TIMER:
473 if (!FD_ISSET(item->info.timer.fd, set))
476 if (read(item->info.timer.fd, &expired_count, sizeof(expired_count)) == sizeof(expired_count)) {
477 DbgPrint("Expired %d times\n", expired_count);
478 if (item->event_cb(svc_ctx, item->cbdata) >= 0)
481 ErrPrint("read: %s\n", strerror(errno));
484 if (!eina_list_data_find(svc_ctx->event_list, item))
487 svc_ctx->event_list = eina_list_remove(svc_ctx->event_list, item);
488 if (close(item->info.timer.fd) < 0)
489 ErrPrint("close: %s\n", strerror(errno));
493 ErrPrint("Unknown event: %d\n", item->type);
500 * Accept new client connections
501 * And create a new thread for service.
503 * Create Client threads & Destroying them
506 static void *server_main(void *data)
508 struct service_context *svc_ctx = data;
516 struct packet_info *packet_info;
518 DbgPrint("Server thread is activated\n");
520 fd = update_fdset(svc_ctx, &set);
521 memcpy(&except_set, &set, sizeof(set));
523 ret = select(fd, &set, NULL, &except_set, NULL);
526 if (errno == EINTR) {
527 DbgPrint("INTERRUPTED\n");
530 ErrPrint("Error: %s\n", strerror(errno));
532 } else if (ret == 0) {
533 ErrPrint("Timeout\n");
538 if (FD_ISSET(svc_ctx->fd, &set)) {
539 client_fd = secure_socket_get_connection_handle(svc_ctx->fd);
541 ErrPrint("Failed to establish a new connection [%d]\n", svc_ctx->fd);
546 tcb = tcb_create(svc_ctx, client_fd);
548 ErrPrint("Failed to create a new TCB: %d (%d)\n", client_fd, svc_ctx->fd);
549 secure_socket_destroy_handle(client_fd);
553 if (FD_ISSET(svc_ctx->tcb_pipe[PIPE_READ], &set)) {
554 if (read(svc_ctx->tcb_pipe[PIPE_READ], &tcb, sizeof(tcb)) != sizeof(tcb)) {
555 ErrPrint("Unable to read pipe: %s\n", strerror(errno));
561 ErrPrint("Terminate service thread\n");
568 * Invoke the service thread main, to notify the termination of a TCB
570 ret = svc_ctx->service_thread_main(tcb, NULL, svc_ctx->service_thread_data);
573 * at this time, the client thread can access this tcb.
574 * how can I protect this TCB from deletion without disturbing the server thread?
576 tcb_destroy(svc_ctx, tcb);
579 if (FD_ISSET(svc_ctx->evt_pipe[PIPE_READ], &set)) {
580 if (read(svc_ctx->evt_pipe[PIPE_READ], &evt_ch, sizeof(evt_ch)) != sizeof(evt_ch)) {
581 ErrPrint("Unable to read pipe: %s\n", strerror(errno));
586 CRITICAL_SECTION_BEGIN(&svc_ctx->packet_list_lock);
587 packet_info = eina_list_nth(svc_ctx->packet_list, 0);
588 svc_ctx->packet_list = eina_list_remove(svc_ctx->packet_list, packet_info);
589 CRITICAL_SECTION_END(&svc_ctx->packet_list_lock);
594 * What happens if the client thread is terminated, so the packet_info->tcb is deleted
595 * while processing svc_ctx->service_thread_main?
597 ret = svc_ctx->service_thread_main(packet_info->tcb, packet_info->packet, svc_ctx->service_thread_data);
599 ErrPrint("Service thread returns: %d\n", ret);
601 packet_destroy(packet_info->packet);
606 processing_timer_event(svc_ctx, &set);
607 /* If there is no such triggered FD? */
611 * Consuming all pended packets before terminates server thread.
613 * If the server thread is terminated, we should flush all pended packets.
614 * And we should services them.
615 * While processing this routine, the mutex is locked.
616 * So every other client thread will be slowed down, sequently, every clients can meet problems.
617 * But in case of termination of server thread, there could be systemetic problem.
618 * This only should be happenes while terminating the master daemon process.
620 CRITICAL_SECTION_BEGIN(&svc_ctx->packet_list_lock);
621 EINA_LIST_FREE(svc_ctx->packet_list, packet_info) {
622 ret = read(svc_ctx->evt_pipe[PIPE_READ], &evt_ch, sizeof(evt_ch));
623 DbgPrint("Flushing pipe: %d (%c)\n", ret, evt_ch);
624 ret = svc_ctx->service_thread_main(packet_info->tcb, packet_info->packet, svc_ctx->service_thread_data);
626 ErrPrint("Service thread returns: %d\n", ret);
627 packet_destroy(packet_info->packet);
630 CRITICAL_SECTION_END(&svc_ctx->packet_list_lock);
632 tcb_teminate_all(svc_ctx);
640 HAPI struct service_context *service_common_create(const char *addr, int (*service_thread_main)(struct tcb *tcb, struct packet *packet, void *data), void *data)
643 struct service_context *svc_ctx;
645 if (!service_thread_main || !addr) {
646 ErrPrint("Invalid argument\n");
650 if (unlink(addr) < 0)
651 ErrPrint("[%s] - %s\n", addr, strerror(errno));
653 svc_ctx = calloc(1, sizeof(*svc_ctx));
655 ErrPrint("Heap: %s\n", strerror(errno));
659 svc_ctx->fd = secure_socket_create_server(addr);
660 if (svc_ctx->fd < 0) {
665 svc_ctx->service_thread_main = service_thread_main;
666 svc_ctx->service_thread_data = data;
668 if (fcntl(svc_ctx->fd, F_SETFD, FD_CLOEXEC) < 0)
669 ErrPrint("fcntl: %s\n", strerror(errno));
671 if (fcntl(svc_ctx->fd, F_SETFL, O_NONBLOCK) < 0)
672 ErrPrint("fcntl: %s\n", strerror(errno));
674 if (pipe2(svc_ctx->evt_pipe, O_NONBLOCK | O_CLOEXEC) < 0) {
675 ErrPrint("pipe: %d\n", strerror(errno));
676 secure_socket_destroy_handle(svc_ctx->fd);
681 if (pipe2(svc_ctx->tcb_pipe, O_NONBLOCK | O_CLOEXEC) < 0) {
682 ErrPrint("pipe: %s\n", strerror(errno));
683 CLOSE_PIPE(svc_ctx->evt_pipe);
684 secure_socket_destroy_handle(svc_ctx->fd);
689 status = pthread_mutex_init(&svc_ctx->packet_list_lock, NULL);
691 ErrPrint("Unable to create a mutex: %s\n", strerror(status));
692 CLOSE_PIPE(svc_ctx->evt_pipe);
693 CLOSE_PIPE(svc_ctx->tcb_pipe);
694 secure_socket_destroy_handle(svc_ctx->fd);
699 DbgPrint("Creating server thread\n");
700 status = pthread_create(&svc_ctx->server_thid, NULL, server_main, svc_ctx);
702 ErrPrint("Unable to create a thread for shortcut service: %s\n", strerror(status));
703 status = pthread_mutex_destroy(&svc_ctx->packet_list_lock);
705 ErrPrint("Error: %s\n", strerror(status));
706 CLOSE_PIPE(svc_ctx->evt_pipe);
707 CLOSE_PIPE(svc_ctx->tcb_pipe);
708 secure_socket_destroy_handle(svc_ctx->fd);
715 * To give a chance to run for server thread.
727 HAPI int service_common_destroy(struct service_context *svc_ctx)
737 * Terminate server thread
739 if (write(svc_ctx->tcb_pipe[PIPE_WRITE], &status, sizeof(status)) != sizeof(status))
740 ErrPrint("Failed to write: %s\n", strerror(errno));
742 status = pthread_join(svc_ctx->server_thid, &ret);
744 ErrPrint("Join: %s\n", strerror(status));
746 DbgPrint("Thread returns: %d\n", (int)ret);
748 secure_socket_destroy_handle(svc_ctx->fd);
750 status = pthread_mutex_destroy(&svc_ctx->packet_list_lock);
752 ErrPrint("Unable to destroy a mutex: %s\n", strerror(status));
754 CLOSE_PIPE(svc_ctx->evt_pipe);
755 CLOSE_PIPE(svc_ctx->tcb_pipe);
764 HAPI int tcb_fd(struct tcb *tcb)
776 HAPI int tcb_client_type(struct tcb *tcb)
788 HAPI int tcb_client_type_set(struct tcb *tcb, enum tcb_type type)
793 DbgPrint("TCB[%p] Client type is changed to %d from %d\n", tcb, type, tcb->type);
802 HAPI struct service_context *tcb_svc_ctx(struct tcb *tcb)
814 HAPI int service_common_unicast_packet(struct tcb *tcb, struct packet *packet)
816 struct service_context *svc_ctx;
817 if (!tcb || !packet) {
818 DbgPrint("Invalid unicast: tcb[%p], packet[%p]\n", tcb, packet);
822 svc_ctx = tcb->svc_ctx;
824 DbgPrint("Unicast packet\n");
825 return secure_socket_send(tcb->fd, (void *)packet_data(packet), packet_size(packet));
832 HAPI int service_common_multicast_packet(struct tcb *tcb, struct packet *packet, int type)
836 struct service_context *svc_ctx;
839 if (!tcb || !packet) {
840 DbgPrint("Invalid multicast: tcb[%p], packet[%p]\n", tcb, packet);
844 svc_ctx = tcb->svc_ctx;
846 DbgPrint("Multicasting packets\n");
847 EINA_LIST_FOREACH(svc_ctx->tcb_list, l, target) {
848 if (target == tcb || target->type != type) {
849 DbgPrint("Skip target: %p(%d) == %p/%d\n", target, target->type, tcb, type);
853 ret = secure_socket_send(target->fd, (void *)packet_data(packet), packet_size(packet));
855 ErrPrint("Failed to send packet: %d\n", ret);
857 DbgPrint("Finish to multicast packet\n");
865 HAPI struct service_event_item *service_common_add_timer(struct service_context *svc_ctx, double timer, int (*timer_cb)(struct service_context *svc_cx, void *data), void *data)
867 struct service_event_item *item;
868 struct itimerspec spec;
870 item = calloc(1, sizeof(*item));
872 ErrPrint("Heap: %s\n", strerror(errno));
876 item->type = SERVICE_EVENT_TIMER;
877 item->info.timer.fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
878 if (item->info.timer.fd < 0) {
879 ErrPrint("Error: %s\n", strerror(errno));
884 spec.it_interval.tv_sec = (time_t)timer;
885 spec.it_interval.tv_nsec = (timer - spec.it_interval.tv_sec) * 1000000000;
886 spec.it_value.tv_sec = 0;
887 spec.it_value.tv_nsec = 0;
889 if (timerfd_settime(item->info.timer.fd, 0, &spec, NULL) < 0) {
890 ErrPrint("Error: %s\n", strerror(errno));
891 if (close(item->info.timer.fd) < 0)
892 ErrPrint("close: %s\n", strerror(errno));
897 item->event_cb = timer_cb;
900 svc_ctx->event_list = eina_list_append(svc_ctx->event_list, item);
908 HAPI int service_common_del_timer(struct service_context *svc_ctx, struct service_event_item *item)
910 if (!eina_list_data_find(svc_ctx->event_list, item)) {
911 ErrPrint("Invalid event item\n");
915 svc_ctx->event_list = eina_list_remove(svc_ctx->event_list, item);
917 if (close(item->info.timer.fd) < 0)
918 ErrPrint("close: %s\n", strerror(errno));
923 HAPI int service_common_fd(struct service_context *ctx)