Update SMACK, Fix a crash of terminating sequence, etc, ...
[apps/livebox/data-provider-master.git] / src / service_common.c
index 8b5405f..d6d4007 100644 (file)
@@ -90,6 +90,7 @@ struct tcb { /* Thread controll block */
        pthread_t thid; /*!< Thread Id */
        int fd; /*!< Connection handle */
        enum tcb_type type;
+       int ctrl_pipe[PIPE_MAX];
 };
 
 /*!
@@ -109,6 +110,7 @@ static void *client_packet_pump_main(void *data)
        int recv_offset;
        int pid;
        int ret;
+       int fd;
        char evt_ch = EVT_CH;
        enum {
                RECV_INIT,
@@ -128,7 +130,9 @@ static void *client_packet_pump_main(void *data)
        while (ret == 0) {
                FD_ZERO(&set);
                FD_SET(tcb->fd, &set);
-               ret = select(tcb->fd + 1, &set, NULL, NULL, NULL);
+               FD_SET(tcb->ctrl_pipe[PIPE_READ], &set);
+               fd = tcb->fd > tcb->ctrl_pipe[PIPE_READ] ? tcb->fd : tcb->ctrl_pipe[PIPE_READ];
+               ret = select(fd + 1, &set, NULL, NULL, NULL);
                if (ret < 0) {
                        ret = -errno;
                        if (errno == EINTR) {
@@ -148,6 +152,14 @@ static void *client_packet_pump_main(void *data)
                        break;
                }
 
+               if (FD_ISSET(tcb->ctrl_pipe[PIPE_READ], &set)) {
+                       DbgPrint("Thread is canceled\n");
+                       ret = -ECANCELED;
+                       free(ptr);
+                       ptr = NULL;
+                       break;
+               }
+
                if (!FD_ISSET(tcb->fd, &set)) {
                        ErrPrint("Unexpected handler is toggled\n");
                        ret = -EINVAL;
@@ -321,6 +333,12 @@ static inline struct tcb *tcb_create(struct service_context *svc_ctx, int fd)
                return NULL;
        }
 
+       if (pipe2(tcb->ctrl_pipe, O_NONBLOCK | O_CLOEXEC) < 0) {
+               ErrPrint("pipe2: %s\n", strerror(errno));
+               free(tcb);
+               return NULL;
+       }
+
        tcb->fd = fd;
        tcb->svc_ctx = svc_ctx;
        tcb->type = TCB_CLIENT_TYPE_APP;
@@ -329,6 +347,7 @@ static inline struct tcb *tcb_create(struct service_context *svc_ctx, int fd)
        status = pthread_create(&tcb->thid, NULL, client_packet_pump_main, tcb);
        if (status != 0) {
                ErrPrint("Unable to create a new thread: %s\n", strerror(status));
+               CLOSE_PIPE(tcb->ctrl_pipe);
                free(tcb);
                return NULL;
        }
@@ -346,6 +365,7 @@ static inline void tcb_teminate_all(struct service_context *svc_ctx)
        struct tcb *tcb;
        void *ret;
        int status;
+       char ch = EVT_END_CH;
 
        /*!
         * We don't need to make critical section on here.
@@ -356,7 +376,8 @@ static inline void tcb_teminate_all(struct service_context *svc_ctx)
                /*!
                 * ASSERT(tcb->fd >= 0);
                 */
-               secure_socket_destroy_handle(tcb->fd);
+               if (write(tcb->ctrl_pipe[PIPE_WRITE], &ch, sizeof(ch)) != sizeof(ch))
+                       ErrPrint("write: %s\n", strerror(errno));
 
                status = pthread_join(tcb->thid, &ret);
                if (status != 0)
@@ -364,6 +385,9 @@ static inline void tcb_teminate_all(struct service_context *svc_ctx)
                else
                        DbgPrint("Thread returns: %d\n", (int)ret);
 
+               secure_socket_destroy_handle(tcb->fd);
+
+               CLOSE_PIPE(tcb->ctrl_pipe);
                free(tcb);
        }
 }
@@ -376,13 +400,15 @@ static inline void tcb_destroy(struct service_context *svc_ctx, struct tcb *tcb)
 {
        void *ret;
        int status;
+       char ch = EVT_END_CH;
 
        svc_ctx->tcb_list = eina_list_remove(svc_ctx->tcb_list, tcb);
        /*!
         * ASSERT(tcb->fd >= 0);
         * Close the connection, and then collecting the return value of thread
         */
-       secure_socket_destroy_handle(tcb->fd);
+       if (write(tcb->ctrl_pipe[PIPE_WRITE], &ch, sizeof(ch)) != sizeof(ch))
+               ErrPrint("write: %s\n", strerror(errno));
 
        status = pthread_join(tcb->thid, &ret);
        if (status != 0)
@@ -390,6 +416,9 @@ static inline void tcb_destroy(struct service_context *svc_ctx, struct tcb *tcb)
        else
                DbgPrint("Thread returns: %d\n", (int)ret);
 
+       secure_socket_destroy_handle(tcb->fd);
+
+       CLOSE_PIPE(tcb->ctrl_pipe);
        free(tcb);
 }
 
@@ -478,6 +507,7 @@ static void *server_main(void *data)
 {
        struct service_context *svc_ctx = data;
        fd_set set;
+       fd_set except_set;
        int ret;
        int client_fd;
        struct tcb *tcb;
@@ -488,8 +518,9 @@ static void *server_main(void *data)
        DbgPrint("Server thread is activated\n");
        while (1) {
                fd = update_fdset(svc_ctx, &set);
+               memcpy(&except_set, &set, sizeof(set));
 
-               ret = select(fd, &set, NULL, NULL, NULL);
+               ret = select(fd, &set, NULL, &except_set, NULL);
                if (ret < 0) {
                        ret = -errno;
                        if (errno == EINTR) {
@@ -526,6 +557,12 @@ static void *server_main(void *data)
                                break;
                        }
 
+                       if (!tcb) {
+                               ErrPrint("Terminate service thread\n");
+                               ret = -ECANCELED;
+                               break;
+                       }
+
                        /*!
                         * \note
                         * Invoke the service thread main, to notify the termination of a TCB
@@ -551,17 +588,19 @@ static void *server_main(void *data)
                        svc_ctx->packet_list = eina_list_remove(svc_ctx->packet_list, packet_info);
                        CRITICAL_SECTION_END(&svc_ctx->packet_list_lock);
 
-                       /*!
-                        * \CRITICAL
-                        * What happens if the client thread is terminated, so the packet_info->tcb is deleted
-                        * while processing svc_ctx->service_thread_main?
-                        */
-                       ret = svc_ctx->service_thread_main(packet_info->tcb, packet_info->packet, svc_ctx->service_thread_data);
-                       if (ret < 0)
-                               ErrPrint("Service thread returns: %d\n", ret);
-
-                       packet_destroy(packet_info->packet);
-                       free(packet_info);
+                       if (packet_info) {
+                               /*!
+                                * \CRITICAL
+                                * What happens if the client thread is terminated, so the packet_info->tcb is deleted
+                                * while processing svc_ctx->service_thread_main?
+                                */
+                               ret = svc_ctx->service_thread_main(packet_info->tcb, packet_info->packet, svc_ctx->service_thread_data);
+                               if (ret < 0)
+                                       ErrPrint("Service thread returns: %d\n", ret);
+
+                               packet_destroy(packet_info->packet);
+                               free(packet_info);
+                       }
                }
 
                processing_timer_event(svc_ctx, &set);
@@ -671,6 +710,13 @@ HAPI struct service_context *service_common_create(const char *addr, int (*servi
                return NULL;
        }
 
+       /*!
+        * \note
+        * To give a chance to run for server thread.
+        */
+       DbgPrint("Yield\n");
+       pthread_yield();
+
        return svc_ctx;
 }
 
@@ -680,7 +726,7 @@ HAPI struct service_context *service_common_create(const char *addr, int (*servi
  */
 HAPI int service_common_destroy(struct service_context *svc_ctx)
 {
-       int status;
+       int status = 0;
        void *ret;
 
        if (!svc_ctx)
@@ -690,7 +736,8 @@ HAPI int service_common_destroy(struct service_context *svc_ctx)
         * \note
         * Terminate server thread
         */
-       secure_socket_destroy_handle(svc_ctx->fd);
+       if (write(svc_ctx->tcb_pipe[PIPE_WRITE], &status, sizeof(status)) != sizeof(status))
+               ErrPrint("Failed to write: %s\n", strerror(errno));
 
        status = pthread_join(svc_ctx->server_thid, &ret);
        if (status != 0)
@@ -698,6 +745,8 @@ HAPI int service_common_destroy(struct service_context *svc_ctx)
        else
                DbgPrint("Thread returns: %d\n", (int)ret);
 
+       secure_socket_destroy_handle(svc_ctx->fd);
+
        status = pthread_mutex_destroy(&svc_ctx->packet_list_lock);
        if (status != 0)
                ErrPrint("Unable to destroy a mutex: %s\n", strerror(status));
@@ -839,7 +888,8 @@ HAPI struct service_event_item *service_common_add_timer(struct service_context
 
        if (timerfd_settime(item->info.timer.fd, 0, &spec, NULL) < 0) {
                ErrPrint("Error: %s\n", strerror(errno));
-               close(item->info.timer.fd);
+               if (close(item->info.timer.fd) < 0)
+                       ErrPrint("close: %s\n", strerror(errno));
                free(item);
                return NULL;
        }
@@ -864,9 +914,15 @@ HAPI int service_common_del_timer(struct service_context *svc_ctx, struct servic
 
        svc_ctx->event_list = eina_list_remove(svc_ctx->event_list, item);
 
-       close(item->info.timer.fd);
+       if (close(item->info.timer.fd) < 0)
+               ErrPrint("close: %s\n", strerror(errno));
        free(item);
        return 0;
 }
 
+HAPI int service_common_fd(struct service_context *ctx)
+{
+       return ctx->fd;
+}
+
 /* End of a file */