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>
32 #if defined(HAVE_LIVEBOX)
33 #include <dynamicbox_errno.h>
35 #include <lite-errno.h>
38 #include "service_common.h"
44 #define EVT_END_CH 'x'
45 #define DEFAULT_TIMEOUT 2.0f
49 struct service_event_item {
60 int (*event_cb)(struct service_context *svc_cx, void *data);
64 struct tcb_event_cbdata {
66 void (*cb)(struct service_context *svc_ctx, struct tcb *tcb, void *data);
72 * Server information and global (only in this file-scope) variables are defined
74 struct service_context {
75 pthread_t server_thid; /*!< Server thread Id */
76 int fd; /*!< Server socket handle */
78 Eina_List *tcb_list; /*!< TCB list, list of every thread for client connections */
79 pthread_mutex_t tcb_list_lock;
81 Eina_List *packet_list;
82 pthread_mutex_t packet_list_lock;
83 int evt_pipe[PIPE_MAX];
84 int tcb_pipe[PIPE_MAX];
86 int (*service_thread_main)(struct tcb *tcb, struct packet *packet, void *data);
87 void *service_thread_data;
89 Eina_List *event_list;
91 Eina_List *tcb_create_cb_list;
92 Eina_List *tcb_destroy_cb_list;
97 struct packet *packet;
102 * Thread Control Block
103 * - The main server will create a thread for every client connections.
104 * When a new client is comming to us, this TCB block will be allocated and initialized.
106 struct tcb { /* Thread controll block */
107 struct service_context *svc_ctx;
108 pthread_t thid; /*!< Thread Id */
109 int fd; /*!< Connection handle */
111 int ctrl_pipe[PIPE_MAX];
112 pid_t pid; /*!< Keep the PID of client, if the client is remote one, this will be -1 */
116 * Do services for clients
117 * Routing packets to destination processes.
120 static void *client_packet_pump_main(void *data)
122 struct tcb *tcb = data;
123 struct service_context *svc_ctx = tcb->svc_ctx;
124 struct packet *packet = NULL;
128 int packet_offset = 0;
132 char evt_ch = EVT_CH;
139 struct packet_info *packet_info;
143 recv_state = RECV_INIT;
146 * To escape from the switch statement, we use this ret value
150 FD_SET(tcb->fd, &set);
151 FD_SET(tcb->ctrl_pipe[PIPE_READ], &set);
152 fd = tcb->fd > tcb->ctrl_pipe[PIPE_READ] ? tcb->fd : tcb->ctrl_pipe[PIPE_READ];
153 ret = select(fd + 1, &set, NULL, NULL, NULL);
156 if (errno == EINTR) {
157 ErrPrint("INTERRUPTED\n");
161 ErrPrint("Error: %s\n", strerror(errno));
165 } else if (ret == 0) {
166 ErrPrint("Timeout\n");
173 if (FD_ISSET(tcb->ctrl_pipe[PIPE_READ], &set)) {
174 DbgPrint("Thread is canceled\n");
181 if (!FD_ISSET(tcb->fd, &set)) {
182 ErrPrint("Unexpected handler is toggled\n");
191 * Service!!! Receive packet & route packet
193 switch (recv_state) {
195 size = packet_header_size();
201 ErrPrint("Heap: %s\n", strerror(errno));
205 recv_state = RECV_HEADER;
206 /* Go through, don't break from here */
208 ret = secure_socket_recv(tcb->fd, ptr, size - recv_offset, &tcb->pid);
221 if (recv_offset == size) {
222 packet = packet_build(packet, packet_offset, ptr, size);
230 packet_offset += recv_offset;
232 size = packet_payload_size(packet);
234 recv_state = RECV_DONE;
239 recv_state = RECV_PAYLOAD;
244 ErrPrint("Heap: %s\n", strerror(errno));
250 ret = secure_socket_recv(tcb->fd, ptr, size - recv_offset, &tcb->pid);
263 if (recv_offset == size) {
264 packet = packet_build(packet, packet_offset, ptr, size);
272 packet_offset += recv_offset;
274 recv_state = RECV_DONE;
284 if (recv_state == RECV_DONE) {
286 * Push this packet to the packet list with TCB
287 * Then the service main function will get this.
289 packet_info = malloc(sizeof(*packet_info));
292 ErrPrint("Heap: %s\n", strerror(errno));
293 packet_destroy(packet);
297 packet_info->packet = packet;
298 packet_info->tcb = tcb;
300 CRITICAL_SECTION_BEGIN(&svc_ctx->packet_list_lock);
301 svc_ctx->packet_list = eina_list_append(svc_ctx->packet_list, packet_info);
302 CRITICAL_SECTION_END(&svc_ctx->packet_list_lock);
304 if (write(svc_ctx->evt_pipe[PIPE_WRITE], &evt_ch, sizeof(evt_ch)) != sizeof(evt_ch)) {
306 ErrPrint("Unable to write a pipe: %s\n", strerror(errno));
307 CRITICAL_SECTION_BEGIN(&svc_ctx->packet_list_lock);
308 svc_ctx->packet_list = eina_list_remove(svc_ctx->packet_list, packet_info);
309 CRITICAL_SECTION_END(&svc_ctx->packet_list_lock);
311 packet_destroy(packet);
312 DbgFree(packet_info);
313 ErrPrint("Terminate thread: %p\n", tcb);
316 DbgPrint("Packet received: %d bytes\n", packet_offset);
317 recv_state = RECV_INIT;
325 CRITICAL_SECTION_BEGIN(&svc_ctx->packet_list_lock);
326 EINA_LIST_FOREACH(svc_ctx->packet_list, l, packet_info) {
327 if (packet_info->tcb == tcb) {
328 DbgPrint("Reset ptr of the TCB[%p] in the list of packet info\n", tcb);
329 packet_info->tcb = NULL;
332 CRITICAL_SECTION_END(&svc_ctx->packet_list_lock);
336 * Emit a signal to collect this TCB from the SERVER THREAD.
338 if (write(svc_ctx->tcb_pipe[PIPE_WRITE], &tcb, sizeof(tcb)) != sizeof(tcb)) {
339 ErrPrint("Unable to write pipe: %s\n", strerror(errno));
349 HAPI int service_register_tcb_callback(struct service_context *svc_ctx, struct tcb *tcb, enum tcb_event_type event, void (*cb)(struct service_context *svc_ctx, struct tcb *tcb, void *data), void *data)
351 struct tcb_event_cbdata *cbdata;
353 cbdata = malloc(sizeof(*cbdata));
355 ErrPrint("Heap: %s\n", strerror(errno));
356 return DBOX_STATUS_ERROR_OUT_OF_MEMORY;
364 case TCB_EVENT_CREATE:
366 DbgPrint("To catch the create event of TCB does not requires \"tcb\" handle\n");
368 svc_ctx->tcb_create_cb_list = eina_list_append(svc_ctx->tcb_create_cb_list, cbdata);
370 case TCB_EVENT_DESTROY:
371 svc_ctx->tcb_destroy_cb_list = eina_list_append(svc_ctx->tcb_destroy_cb_list, cbdata);
375 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
378 return DBOX_STATUS_ERROR_NONE;
385 HAPI int service_unregister_tcb_callback(struct service_context *svc_ctx, struct tcb *tcb, enum tcb_event_type event, void (*cb)(struct service_context *svc_ctx, struct tcb *tcb, void *data), void *data)
387 struct tcb_event_cbdata *cbdata;
391 case TCB_EVENT_CREATE:
392 EINA_LIST_FOREACH(svc_ctx->tcb_create_cb_list, l, cbdata) {
393 if (cbdata->tcb == tcb && cbdata->cb == cb && cbdata->data == data) {
394 svc_ctx->tcb_create_cb_list = eina_list_remove(svc_ctx->tcb_create_cb_list, cbdata);
396 return DBOX_STATUS_ERROR_NONE;
400 case TCB_EVENT_DESTROY:
401 EINA_LIST_FOREACH(svc_ctx->tcb_destroy_cb_list, l, cbdata) {
402 if (cbdata->tcb == tcb && cbdata->cb == cb && cbdata->data == data) {
403 svc_ctx->tcb_destroy_cb_list = eina_list_remove(svc_ctx->tcb_destroy_cb_list, cbdata);
405 return DBOX_STATUS_ERROR_NONE;
410 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
413 return DBOX_STATUS_ERROR_NOT_EXIST;
420 static inline struct tcb *tcb_create(struct service_context *svc_ctx, int fd)
424 struct tcb_event_cbdata *cbdata;
428 tcb = malloc(sizeof(*tcb));
430 ErrPrint("Heap: %s\n", strerror(errno));
434 if (pipe2(tcb->ctrl_pipe, O_CLOEXEC) < 0) {
435 ErrPrint("pipe2: %s\n", strerror(errno));
441 tcb->svc_ctx = svc_ctx;
442 tcb->type = TCB_CLIENT_TYPE_APP;
445 DbgPrint("Create a new service thread [%d]\n", fd);
446 status = pthread_create(&tcb->thid, NULL, client_packet_pump_main, tcb);
448 ErrPrint("Unable to create a new thread: %s\n", strerror(status));
449 CLOSE_PIPE(tcb->ctrl_pipe);
454 CRITICAL_SECTION_BEGIN(&svc_ctx->tcb_list_lock);
455 svc_ctx->tcb_list = eina_list_append(svc_ctx->tcb_list, tcb);
456 CRITICAL_SECTION_END(&svc_ctx->tcb_list_lock);
458 EINA_LIST_FOREACH_SAFE(svc_ctx->tcb_create_cb_list, l, n, cbdata) {
461 ErrPrint("invalid CB\n");
462 svc_ctx->tcb_create_cb_list = eina_list_remove(svc_ctx->tcb_create_cb_list, cbdata);
467 cbdata->cb(svc_ctx, tcb, cbdata->data);
477 static inline void tcb_teminate_all(struct service_context *svc_ctx)
482 char ch = EVT_END_CH;
485 * We don't need to make critical section on here.
486 * If we call this after terminate the server thread first.
487 * Then there is no other thread to access tcb_list.
489 EINA_LIST_FREE(svc_ctx->tcb_list, tcb) {
491 * ASSERT(tcb->fd >= 0);
493 if (write(tcb->ctrl_pipe[PIPE_WRITE], &ch, sizeof(ch)) != sizeof(ch)) {
494 ErrPrint("write: %s\n", strerror(errno));
497 status = pthread_join(tcb->thid, &ret);
499 ErrPrint("Unable to join a thread: %s\n", strerror(status));
501 DbgPrint("Thread returns: %p\n", ret);
504 secure_socket_destroy_handle(tcb->fd);
506 CLOSE_PIPE(tcb->ctrl_pipe);
515 static inline void tcb_destroy(struct service_context *svc_ctx, struct tcb *tcb)
519 char ch = EVT_END_CH;
520 struct tcb_event_cbdata *cbdata;
524 EINA_LIST_FOREACH_SAFE(svc_ctx->tcb_destroy_cb_list, l, n, cbdata) {
527 ErrPrint("invalid CB\n");
528 svc_ctx->tcb_destroy_cb_list = eina_list_remove(svc_ctx->tcb_destroy_cb_list, cbdata);
533 if (cbdata->tcb != tcb) {
537 cbdata->cb(svc_ctx, tcb, cbdata->data);
539 if (eina_list_data_find(svc_ctx->tcb_destroy_cb_list, cbdata)) {
540 svc_ctx->tcb_destroy_cb_list = eina_list_remove(svc_ctx->tcb_destroy_cb_list, cbdata);
545 CRITICAL_SECTION_BEGIN(&svc_ctx->tcb_list_lock);
546 svc_ctx->tcb_list = eina_list_remove(svc_ctx->tcb_list, tcb);
547 CRITICAL_SECTION_END(&svc_ctx->tcb_list_lock);
549 * ASSERT(tcb->fd >= 0);
550 * Close the connection, and then collecting the return value of thread
552 if (write(tcb->ctrl_pipe[PIPE_WRITE], &ch, sizeof(ch)) != sizeof(ch)) {
553 ErrPrint("write: %s\n", strerror(errno));
556 status = pthread_join(tcb->thid, &ret);
558 ErrPrint("Unable to join a thread: %s\n", strerror(status));
560 DbgPrint("Thread returns: %p\n", ret);
563 secure_socket_destroy_handle(tcb->fd);
565 CLOSE_PIPE(tcb->ctrl_pipe);
573 static inline int update_fdset(struct service_context *svc_ctx, fd_set *set)
576 struct service_event_item *item;
581 FD_SET(svc_ctx->fd, set);
584 FD_SET(svc_ctx->tcb_pipe[PIPE_READ], set);
585 if (svc_ctx->tcb_pipe[PIPE_READ] > fd) {
586 fd = svc_ctx->tcb_pipe[PIPE_READ];
589 FD_SET(svc_ctx->evt_pipe[PIPE_READ], set);
590 if (svc_ctx->evt_pipe[PIPE_READ] > fd) {
591 fd = svc_ctx->evt_pipe[PIPE_READ];
594 EINA_LIST_FOREACH(svc_ctx->event_list, l, item) {
595 if (item->type == SERVICE_EVENT_TIMER) {
596 FD_SET(item->info.timer.fd, set);
597 if (fd < item->info.timer.fd) {
598 fd = item->info.timer.fd;
610 static inline void processing_timer_event(struct service_context *svc_ctx, fd_set *set)
612 uint64_t expired_count;
615 struct service_event_item *item;
617 EINA_LIST_FOREACH_SAFE(svc_ctx->event_list, l, n, item) {
618 switch (item->type) {
619 case SERVICE_EVENT_TIMER:
620 if (!FD_ISSET(item->info.timer.fd, set)) {
624 if (read(item->info.timer.fd, &expired_count, sizeof(expired_count)) == sizeof(expired_count)) {
625 DbgPrint("Expired %d times\n", expired_count);
626 if (item->event_cb(svc_ctx, item->cbdata) >= 0) {
630 ErrPrint("read: %s\n", strerror(errno));
633 if (!eina_list_data_find(svc_ctx->event_list, item)) {
637 svc_ctx->event_list = eina_list_remove(svc_ctx->event_list, item);
638 if (close(item->info.timer.fd) < 0) {
639 ErrPrint("close: %s\n", strerror(errno));
644 ErrPrint("Unknown event: %d\n", item->type);
651 * Accept new client connections
652 * And create a new thread for service.
654 * Create Client threads & Destroying them
657 static void *server_main(void *data)
659 struct service_context *svc_ctx = data;
667 struct packet_info *packet_info;
669 DbgPrint("Server thread is activated\n");
671 fd = update_fdset(svc_ctx, &set);
672 memcpy(&except_set, &set, sizeof(set));
674 ret = select(fd, &set, NULL, &except_set, NULL);
677 if (errno == EINTR) {
678 DbgPrint("INTERRUPTED\n");
681 ErrPrint("Error: %s\n", strerror(errno));
683 } else if (ret == 0) {
684 ErrPrint("Timeout\n");
689 if (FD_ISSET(svc_ctx->fd, &set)) {
690 client_fd = secure_socket_get_connection_handle(svc_ctx->fd);
692 ErrPrint("Failed to establish a new connection [%d]\n", svc_ctx->fd);
697 tcb = tcb_create(svc_ctx, client_fd);
699 ErrPrint("Failed to create a new TCB: %d (%d)\n", client_fd, svc_ctx->fd);
700 secure_socket_destroy_handle(client_fd);
704 if (FD_ISSET(svc_ctx->evt_pipe[PIPE_READ], &set)) {
705 if (read(svc_ctx->evt_pipe[PIPE_READ], &evt_ch, sizeof(evt_ch)) != sizeof(evt_ch)) {
706 ErrPrint("Unable to read pipe: %s\n", strerror(errno));
711 CRITICAL_SECTION_BEGIN(&svc_ctx->packet_list_lock);
712 packet_info = eina_list_nth(svc_ctx->packet_list, 0);
713 svc_ctx->packet_list = eina_list_remove(svc_ctx->packet_list, packet_info);
714 CRITICAL_SECTION_END(&svc_ctx->packet_list_lock);
719 * What happens if the client thread is terminated, so the packet_info->tcb is deleted
720 * while processing svc_ctx->service_thread_main?
722 ret = svc_ctx->service_thread_main(packet_info->tcb, packet_info->packet, svc_ctx->service_thread_data);
724 ErrPrint("Service thread returns: %d\n", ret);
727 packet_destroy(packet_info->packet);
728 DbgFree(packet_info);
735 processing_timer_event(svc_ctx, &set);
739 * Destroying TCB should be processed at last.
741 if (FD_ISSET(svc_ctx->tcb_pipe[PIPE_READ], &set)) {
742 Eina_List *lockfree_packet_list;
746 if (read(svc_ctx->tcb_pipe[PIPE_READ], &tcb, sizeof(tcb)) != sizeof(tcb)) {
747 ErrPrint("Unable to read pipe: %s\n", strerror(errno));
753 ErrPrint("Terminate service thread\n");
758 lockfree_packet_list = NULL;
759 CRITICAL_SECTION_BEGIN(&svc_ctx->packet_list_lock);
760 EINA_LIST_FOREACH_SAFE(svc_ctx->packet_list, l, n, packet_info) {
761 if (packet_info->tcb != tcb) {
765 svc_ctx->packet_list = eina_list_remove(svc_ctx->packet_list, packet_info);
766 lockfree_packet_list = eina_list_append(lockfree_packet_list, packet_info);
768 CRITICAL_SECTION_END(&svc_ctx->packet_list_lock);
770 EINA_LIST_FREE(lockfree_packet_list, packet_info) {
771 ret = read(svc_ctx->evt_pipe[PIPE_READ], &evt_ch, sizeof(evt_ch));
772 DbgPrint("Flushing filtered pipe: %d (%c)\n", ret, evt_ch);
773 ret = svc_ctx->service_thread_main(packet_info->tcb, packet_info->packet, svc_ctx->service_thread_data);
775 ErrPrint("Service thread returns: %d\n", ret);
777 packet_destroy(packet_info->packet);
778 DbgFree(packet_info);
783 * Invoke the service thread main, to notify the termination of a TCB
785 ret = svc_ctx->service_thread_main(tcb, NULL, svc_ctx->service_thread_data);
788 * at this time, the client thread can access this tcb.
789 * how can I protect this TCB from deletion without disturbing the server thread?
791 tcb_destroy(svc_ctx, tcb);
794 /* If there is no such triggered FD? */
798 * Consuming all pended packets before terminates server thread.
800 * If the server thread is terminated, we should flush all pended packets.
801 * And we should services them.
802 * While processing this routine, the mutex is locked.
803 * So every other client thread will be slowed down, sequently, every clients can meet problems.
804 * But in case of termination of server thread, there could be systemetic problem.
805 * This only should be happenes while terminating the master daemon process.
807 CRITICAL_SECTION_BEGIN(&svc_ctx->packet_list_lock);
808 EINA_LIST_FREE(svc_ctx->packet_list, packet_info) {
809 ret = read(svc_ctx->evt_pipe[PIPE_READ], &evt_ch, sizeof(evt_ch));
810 DbgPrint("Flushing pipe: %d (%c)\n", ret, evt_ch);
811 ret = svc_ctx->service_thread_main(packet_info->tcb, packet_info->packet, svc_ctx->service_thread_data);
813 ErrPrint("Service thread returns: %d\n", ret);
815 packet_destroy(packet_info->packet);
816 DbgFree(packet_info);
818 CRITICAL_SECTION_END(&svc_ctx->packet_list_lock);
820 tcb_teminate_all(svc_ctx);
828 HAPI struct service_context *service_common_create(const char *addr, int (*service_thread_main)(struct tcb *tcb, struct packet *packet, void *data), void *data)
831 struct service_context *svc_ctx;
833 if (!service_thread_main || !addr) {
834 ErrPrint("Invalid argument\n");
838 if (strncmp(addr, COM_CORE_REMOTE_SCHEME, strlen(COM_CORE_REMOTE_SCHEME))) {
841 offset = strlen(COM_CORE_LOCAL_SCHEME);
842 if (strncmp(addr, COM_CORE_LOCAL_SCHEME, offset)) {
846 if (unlink(addr + offset) < 0) {
847 ErrPrint("[%s] - %s\n", addr, strerror(errno));
851 svc_ctx = calloc(1, sizeof(*svc_ctx));
853 ErrPrint("Heap: %s\n", strerror(errno));
857 svc_ctx->fd = secure_socket_create_server(addr);
858 if (svc_ctx->fd < 0) {
863 svc_ctx->service_thread_main = service_thread_main;
864 svc_ctx->service_thread_data = data;
866 if (fcntl(svc_ctx->fd, F_SETFD, FD_CLOEXEC) < 0) {
867 ErrPrint("fcntl: %s\n", strerror(errno));
870 if (fcntl(svc_ctx->fd, F_SETFL, O_NONBLOCK) < 0) {
871 ErrPrint("fcntl: %s\n", strerror(errno));
874 if (pipe2(svc_ctx->evt_pipe, O_CLOEXEC) < 0) {
875 ErrPrint("pipe: %d\n", strerror(errno));
876 secure_socket_destroy_handle(svc_ctx->fd);
881 if (pipe2(svc_ctx->tcb_pipe, O_CLOEXEC) < 0) {
882 ErrPrint("pipe: %s\n", strerror(errno));
883 CLOSE_PIPE(svc_ctx->evt_pipe);
884 secure_socket_destroy_handle(svc_ctx->fd);
889 status = pthread_mutex_init(&svc_ctx->packet_list_lock, NULL);
891 ErrPrint("Unable to create a mutex: %s\n", strerror(status));
892 CLOSE_PIPE(svc_ctx->evt_pipe);
893 CLOSE_PIPE(svc_ctx->tcb_pipe);
894 secure_socket_destroy_handle(svc_ctx->fd);
899 DbgPrint("Creating server thread\n");
900 status = pthread_create(&svc_ctx->server_thid, NULL, server_main, svc_ctx);
902 ErrPrint("Unable to create a thread for shortcut service: %s\n", strerror(status));
903 status = pthread_mutex_destroy(&svc_ctx->packet_list_lock);
905 ErrPrint("Error: %s\n", strerror(status));
907 CLOSE_PIPE(svc_ctx->evt_pipe);
908 CLOSE_PIPE(svc_ctx->tcb_pipe);
909 secure_socket_destroy_handle(svc_ctx->fd);
916 * To give a chance to run for server thread.
927 HAPI int service_common_destroy(struct service_context *svc_ctx)
938 * Terminate server thread
940 if (write(svc_ctx->tcb_pipe[PIPE_WRITE], &status, sizeof(status)) != sizeof(status)) {
941 ErrPrint("Failed to write: %s\n", strerror(errno));
944 status = pthread_join(svc_ctx->server_thid, &ret);
946 ErrPrint("Join: %s\n", strerror(status));
948 DbgPrint("Thread returns: %p\n", ret);
951 secure_socket_destroy_handle(svc_ctx->fd);
953 status = pthread_mutex_destroy(&svc_ctx->packet_list_lock);
955 ErrPrint("Unable to destroy a mutex: %s\n", strerror(status));
958 CLOSE_PIPE(svc_ctx->evt_pipe);
959 CLOSE_PIPE(svc_ctx->tcb_pipe);
966 * SERVER THREAD or OTHER THREAD (not main)
968 HAPI int tcb_is_valid(struct service_context *svc_ctx, struct tcb *tcb)
974 CRITICAL_SECTION_BEGIN(&svc_ctx->tcb_list_lock);
975 EINA_LIST_FOREACH(svc_ctx->tcb_list, l, tmp) {
976 if (tmp == tcb /* && tcb->svc_ctx == svc_ctx */) {
981 CRITICAL_SECTION_END(&svc_ctx->tcb_list_lock);
990 HAPI int tcb_pid(struct tcb *tcb)
1003 HAPI int tcb_fd(struct tcb *tcb)
1016 HAPI int tcb_client_type(struct tcb *tcb)
1029 HAPI int tcb_client_type_set(struct tcb *tcb, enum tcb_type type)
1035 DbgPrint("TCB[%p] Client type is changed to %d from %d\n", tcb, type, tcb->type);
1044 HAPI struct service_context *tcb_svc_ctx(struct tcb *tcb)
1050 return tcb->svc_ctx;
1057 HAPI int service_common_unicast_packet(struct tcb *tcb, struct packet *packet)
1059 if (!tcb || !packet) {
1060 DbgPrint("Invalid unicast: tcb[%p], packet[%p]\n", tcb, packet);
1064 DbgPrint("Unicast packet\n");
1065 return com_core_send(tcb->fd, (void *)packet_data(packet), packet_size(packet), DEFAULT_TIMEOUT);
1072 HAPI int service_common_multicast_packet(struct tcb *tcb, struct packet *packet, int type)
1076 struct service_context *svc_ctx;
1079 if (!tcb || !packet) {
1080 DbgPrint("Invalid multicast: tcb[%p], packet[%p]\n", tcb, packet);
1084 svc_ctx = tcb->svc_ctx;
1086 DbgPrint("Multicasting packets\n");
1090 * Does not need to make a critical section from here.
1092 EINA_LIST_FOREACH(svc_ctx->tcb_list, l, target) {
1093 if (target == tcb || target->type != type) {
1094 DbgPrint("Skip target: %p(%d) == %p/%d\n", target, target->type, tcb, type);
1098 ret = com_core_send(target->fd, (void *)packet_data(packet), packet_size(packet), DEFAULT_TIMEOUT);
1100 ErrPrint("Failed to send packet: %d\n", ret);
1103 DbgPrint("Finish to multicast packet\n");
1111 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)
1113 struct service_event_item *item;
1115 item = calloc(1, sizeof(*item));
1117 ErrPrint("Heap: %s\n", strerror(errno));
1121 item->type = SERVICE_EVENT_TIMER;
1122 item->info.timer.fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
1123 if (item->info.timer.fd < 0) {
1124 ErrPrint("Error: %s\n", strerror(errno));
1129 if (service_common_update_timer(item, timer) < 0) {
1130 if (close(item->info.timer.fd) < 0) {
1131 ErrPrint("close: %s\n", strerror(errno));
1137 item->event_cb = timer_cb;
1138 item->cbdata = data;
1140 svc_ctx->event_list = eina_list_append(svc_ctx->event_list, item);
1144 HAPI int service_common_update_timer(struct service_event_item *item, double timer)
1146 struct itimerspec spec;
1148 spec.it_interval.tv_sec = (time_t)timer;
1149 spec.it_interval.tv_nsec = (timer - spec.it_interval.tv_sec) * 1000000000;
1151 if (clock_gettime(CLOCK_MONOTONIC, &spec.it_value) < 0) {
1152 ErrPrint("clock_gettime: %s\n", strerror(errno));
1156 spec.it_value.tv_sec += spec.it_interval.tv_sec;
1157 spec.it_value.tv_nsec += spec.it_interval.tv_nsec;
1159 if (timerfd_settime(item->info.timer.fd, TFD_TIMER_ABSTIME, &spec, NULL) < 0) {
1160 ErrPrint("Error: %s\n", strerror(errno));
1164 DbgPrint("Armed interval: %u %u\n", spec.it_interval.tv_sec, spec.it_interval.tv_nsec);
1172 HAPI int service_common_del_timer(struct service_context *svc_ctx, struct service_event_item *item)
1174 if (!eina_list_data_find(svc_ctx->event_list, item)) {
1175 ErrPrint("Invalid event item\n");
1179 svc_ctx->event_list = eina_list_remove(svc_ctx->event_list, item);
1181 if (close(item->info.timer.fd) < 0) {
1182 ErrPrint("close: %s\n", strerror(errno));
1188 HAPI int service_common_fd(struct service_context *ctx)