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>
30 #include "service_common.h"
36 #define EVT_END_CH 'x'
42 * Server information and global (only in this file-scope) variables are defined
45 struct service_context {
46 pthread_t server_thid; /*!< Server thread Id */
47 int fd; /*!< Server socket handle */
49 Eina_List *tcb_list; /*!< TCB list, list of every thread for client connections */
51 Eina_List *packet_list;
52 pthread_mutex_t packet_list_lock;
53 int evt_pipe[PIPE_MAX];
54 int tcb_pipe[PIPE_MAX];
56 int (*service_thread_main)(struct tcb *tcb, struct packet *packet, void *data);
57 void *service_thread_data;
62 struct packet *packet;
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.
71 struct tcb { /* Thread controll block */
72 struct service_context *svc_ctx;
73 pthread_t thid; /*!< Thread Id */
74 int fd; /*!< Connection handle */
79 * Do services for clients
80 * Routing packets to destination processes.
83 static void *client_packet_pump_main(void *data)
85 struct tcb *tcb = data;
86 struct service_context *svc_ctx = tcb->svc_ctx;
87 struct packet *packet;
102 struct packet_info *packet_info;
106 recv_state = RECV_INIT;
107 DbgPrint("Socket data pumping thread is activated\n");
110 * To escape from the switch statement, we use this ret value
114 FD_SET(tcb->fd, &set);
115 ret = select(tcb->fd + 1, &set, NULL, NULL, NULL);
118 if (errno == EINTR) {
119 DbgPrint("INTERRUPTED\n");
123 ErrPrint("Error: %s\n", strerror(errno));
127 } else if (ret == 0) {
128 ErrPrint("Timeout\n");
135 if (!FD_ISSET(tcb->fd, &set)) {
136 ErrPrint("Unexpected handler is toggled\n");
145 * Service!!! Receive packet & route packet
147 switch (recv_state) {
149 size = packet_header_size();
155 ErrPrint("Heap: %s\n", strerror(errno));
159 recv_state = RECV_HEADER;
160 /* Go through, don't break from here */
162 ret = secure_socket_recv(tcb->fd, ptr, size - recv_offset, &pid);
174 if (recv_offset == size) {
175 packet = packet_build(packet, packet_offset, ptr, size);
183 packet_offset += recv_offset;
185 size = packet_payload_size(packet);
187 recv_state = RECV_DONE;
192 recv_state = RECV_PAYLOAD;
197 ErrPrint("Heap: %s\n", strerror(errno));
203 ret = secure_socket_recv(tcb->fd, ptr, size - recv_offset, &pid);
215 if (recv_offset == size) {
216 packet = packet_build(packet, packet_offset, ptr, size);
224 packet_offset += recv_offset;
226 recv_state = RECV_DONE;
236 if (recv_state == RECV_DONE) {
238 * Push this packet to the packet list with TCB
239 * Then the service main function will get this.
241 packet_info = malloc(sizeof(*packet_info));
244 ErrPrint("Heap: %s\n", strerror(errno));
245 packet_destroy(packet);
249 packet_info->packet = packet;
250 packet_info->tcb = tcb;
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);
257 if (write(svc_ctx->evt_pipe[PIPE_WRITE], &evt_ch, sizeof(evt_ch)) != sizeof(evt_ch)) {
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);
264 packet_destroy(packet);
266 ErrPrint("Terminate thread: %p\n", tcb);
269 DbgPrint("Packet received: %d bytes\n", packet_offset);
270 recv_state = RECV_INIT;
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;
282 CRITICAL_SECTION_END(&svc_ctx->packet_list_lock);
286 * Emit a signal to collect this TCB from the SERVER THREAD.
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));
299 static inline struct tcb *tcb_create(struct service_context *svc_ctx, int fd)
304 tcb = malloc(sizeof(*tcb));
306 ErrPrint("Heap: %s\n", strerror(errno));
311 tcb->svc_ctx = svc_ctx;
312 tcb->type = TCB_CLIENT_TYPE_APP;
314 DbgPrint("Create a new service thread [%d]\n", fd);
315 status = pthread_create(&tcb->thid, NULL, client_packet_pump_main, tcb);
317 ErrPrint("Unable to create a new thread: %s\n", strerror(status));
322 svc_ctx->tcb_list = eina_list_append(svc_ctx->tcb_list, tcb);
330 static inline void tcb_teminate_all(struct service_context *svc_ctx)
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.
341 EINA_LIST_FREE(svc_ctx->tcb_list, tcb) {
343 * ASSERT(tcb->fd >= 0);
345 secure_socket_destroy_handle(tcb->fd);
347 status = pthread_join(tcb->thid, &ret);
349 ErrPrint("Unable to join a thread: %s\n", strerror(status));
351 DbgPrint("Thread returns: %d\n", (int)ret);
361 static inline void tcb_destroy(struct service_context *svc_ctx, struct tcb *tcb)
366 svc_ctx->tcb_list = eina_list_remove(svc_ctx->tcb_list, tcb);
368 * ASSERT(tcb->fd >= 0);
369 * Close the connection, and then collecting the return value of thread
371 secure_socket_destroy_handle(tcb->fd);
373 status = pthread_join(tcb->thid, &ret);
375 ErrPrint("Unable to join a thread: %s\n", strerror(status));
377 DbgPrint("Thread returns: %d\n", (int)ret);
383 * Accept new client connections
384 * And create a new thread for service.
386 * Create Client threads & Destroying them
389 static void *server_main(void *data)
391 struct service_context *svc_ctx = data;
398 struct packet_info *packet_info;
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];
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);
411 ret = select(fd, &set, NULL, NULL, NULL);
414 if (errno == EINTR) {
415 DbgPrint("INTERRUPTED\n");
418 ErrPrint("Error: %s\n", strerror(errno));
420 } else if (ret == 0) {
421 ErrPrint("Timeout\n");
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);
430 ErrPrint("Failed to establish the client connection\n");
435 tcb = tcb_create(svc_ctx, client_fd);
437 secure_socket_destroy_handle(client_fd);
439 DbgPrint("Creating TCB[%p]\n", tcb);
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));
449 DbgPrint("Destroying TCB[%p]\n", tcb);
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?
454 tcb_destroy(svc_ctx, tcb);
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));
464 DbgPrint("Event CH: %c\n", evt_ch);
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);
473 * What happens if the client thread is terminated, so the packet_info->tcb is deleted
474 * while processing svc_ctx->service_thread_main?
476 ret = svc_ctx->service_thread_main(packet_info->tcb, packet_info->packet, svc_ctx->service_thread_data);
478 ErrPrint("Service thread returns: %d\n", ret);
480 packet_destroy(packet_info->packet);
484 /* If there is no such triggered FD? */
488 * Consuming all pended packets before terminates server thread.
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.
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);
503 ErrPrint("Service thread returns: %d\n", ret);
504 packet_destroy(packet_info->packet);
507 CRITICAL_SECTION_END(&svc_ctx->packet_list_lock);
509 tcb_teminate_all(svc_ctx);
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)
520 struct service_context *svc_ctx;
522 if (!service_thread_main || !addr) {
523 ErrPrint("Invalid argument\n");
527 if (unlink(addr) < 0)
528 ErrPrint("[%s] - %s\n", addr, strerror(errno));
530 svc_ctx = calloc(1, sizeof(*svc_ctx));
532 ErrPrint("Heap: %s\n", strerror(errno));
536 svc_ctx->fd = secure_socket_create_server(addr);
537 if (svc_ctx->fd < 0) {
542 svc_ctx->service_thread_main = service_thread_main;
543 svc_ctx->service_thread_data = data;
545 if (fcntl(svc_ctx->fd, F_SETFD, FD_CLOEXEC) < 0)
546 ErrPrint("fcntl: %s\n", strerror(errno));
548 if (fcntl(svc_ctx->fd, F_SETFL, O_NONBLOCK) < 0)
549 ErrPrint("fcntl: %s\n", strerror(errno));
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);
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);
566 status = pthread_mutex_init(&svc_ctx->packet_list_lock, NULL);
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);
576 DbgPrint("Creating server thread\n");
577 status = pthread_create(&svc_ctx->server_thid, NULL, server_main, svc_ctx);
579 ErrPrint("Unable to create a thread for shortcut service: %s\n", strerror(status));
580 status = pthread_mutex_destroy(&svc_ctx->packet_list_lock);
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);
597 HAPI int service_common_destroy(struct service_context *svc_ctx)
607 * Terminate server thread
609 secure_socket_destroy_handle(svc_ctx->fd);
611 status = pthread_join(svc_ctx->server_thid, &ret);
613 ErrPrint("Join: %s\n", strerror(status));
615 DbgPrint("Thread returns: %d\n", (int)ret);
617 status = pthread_mutex_destroy(&svc_ctx->packet_list_lock);
619 ErrPrint("Unable to destroy a mutex: %s\n", strerror(status));
621 CLOSE_PIPE(svc_ctx->evt_pipe);
622 CLOSE_PIPE(svc_ctx->tcb_pipe);
631 HAPI int tcb_fd(struct tcb *tcb)
643 HAPI int tcb_client_type(struct tcb *tcb)
655 HAPI int tcb_client_type_set(struct tcb *tcb, enum tcb_type type)
660 DbgPrint("TCB[%p] Client type is changed to %d from %d\n", tcb, type, tcb->type);
669 HAPI struct service_context *tcb_svc_ctx(struct tcb *tcb)
681 HAPI int service_common_unicast_packet(struct tcb *tcb, struct packet *packet)
683 struct service_context *svc_ctx;
687 svc_ctx = tcb->svc_ctx;
689 DbgPrint("Unicast packet\n");
690 return secure_socket_send(tcb->fd, (void *)packet_data(packet), packet_size(packet));
697 HAPI int service_common_multicast_packet(struct tcb *tcb, struct packet *packet, int type)
701 struct service_context *svc_ctx;
707 svc_ctx = tcb->svc_ctx;
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);
716 ret = secure_socket_send(target->fd, (void *)packet_data(packet), packet_size(packet));
718 ErrPrint("Failed to send packet: %d\n", ret);
720 DbgPrint("Finish to multicast packet\n");