daemon/socket: Add support for socket binding
authorSangchul Lee <sc11.lee@samsung.com>
Tue, 18 Apr 2023 07:14:00 +0000 (16:14 +0900)
committer이상철/Tizen Platform Lab(SR)/삼성전자 <sc11.lee@samsung.com>
Wed, 19 Apr 2023 07:54:10 +0000 (16:54 +0900)
Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
src/daemon/espp_service.c
src/daemon/espp_service_priv.h
src/daemon/espp_service_socket.c [new file with mode: 0644]
src/daemon/meson.build

index 9ca05f0748a8aa7a6e365f1bb78e655e4c6ecc35..23d67c1ef02aaf16831a02565d2c70e72ebbf1ea 100644 (file)
@@ -17,9 +17,7 @@
 #include "espp_service_priv.h"
 
 #include <stdio.h>
-#include <stdbool.h>
 #include <getopt.h>
-#include <glib.h>
 #include <sys/stat.h>
 
 static struct sigaction g_int_old_action;
@@ -29,10 +27,7 @@ static struct sigaction g_term_old_action;
 static struct sigaction g_sys_old_action;
 static struct sigaction g_xcpu_old_action;
 
-typedef struct {
-       bool start_service;
-       GMainLoop *mainloop;
-} espp_service_s;
+espp_service_s *g_svc;
 
 static void print_usage()
 {
@@ -83,7 +78,7 @@ static void __sa_handler(int signal)
        sigfillset(&all_mask);
        sigprocmask(SIG_BLOCK, &all_mask, &old_mask);
 
-       /* TODO: release resources */
+       espp_service_deinit_socket(g_svc);
 
        sigprocmask(SIG_SETMASK, &old_mask, NULL);
        /* signal unblock ------------ */
@@ -166,9 +161,9 @@ static void run(espp_service_s *svc)
 
 int main(int argc, char *argv[])
 {
-       espp_service_s svc = { false, NULL };
+       espp_service_s svc = { false, NULL, -1, 0 };
 
-       LOG_INFO("LAUNCH, version[%s]", ESPP_SVC_VERSION);
+       LOG_WARNING("launched, version[%s]", ESPP_SVC_VERSION);
 
        if (get_option(argc, argv, &svc))
                return 1;
@@ -178,22 +173,25 @@ int main(int argc, char *argv[])
                goto exit;
        }
 
+       g_svc = &svc;
+
        initialize_signals();
 
        signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE */
 
        umask(0); /* change the file mode mask */
 
-       /* TODO: init socket */
+       if (espp_service_init_socket(&svc) != 0)
+               goto exit;
 
        run(&svc);
 
-       /* TODO: release socket */
+       espp_service_deinit_socket(&svc);
 
        deinitialize_signals();
 
 exit:
-       LOG_INFO("EXIT");
+       LOG_WARNING("exit");
 
        return 0;
 }
index 94566558c9f6a434b78f155911d1df75c4a663ec..0c855eec7653c0adea25a829ff384060da5720ba 100644 (file)
@@ -26,6 +26,8 @@
 #define ESPP_SVC_VERSION "unknown"
 #endif
 #include <stdlib.h>
+#include <glib.h>
+#include <stdbool.h>
 #ifdef USE_DLOG
 #include <dlog.h>
 #endif
@@ -113,6 +115,16 @@ do {\
        } \
 } while (0)
 
+typedef struct {
+       bool start_service;
+       GMainLoop *mainloop;
+       int fd;
+       pthread_t thread_id;
+} espp_service_s;
+
+int espp_service_init_socket(espp_service_s *svc);
+void espp_service_deinit_socket(espp_service_s *svc);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/src/daemon/espp_service_socket.c b/src/daemon/espp_service_socket.c
new file mode 100644 (file)
index 0000000..9090fdc
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "espp_service_priv.h"
+#include <stdint.h>
+#include <gio/gio.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <pthread.h>
+
+#define ESPP_SERVICE_SOCK "/run/espp_service.socket"
+#define MAX_ERROR_LEN 64
+#define MAX_FUNC_LEN 32
+
+typedef struct {
+       char func[MAX_FUNC_LEN];
+} espp_service_data_from_client_s;
+
+typedef struct {
+       int ret;
+} espp_service_data_from_server_s;
+
+static void *__work_thread_func(void *data)
+{
+       int fd;
+       int ret;
+       char str_error[MAX_ERROR_LEN] = {'\0',};
+       espp_service_data_from_client_s rx_data;
+       espp_service_data_from_server_s tx_data;
+
+       ASSERT(data);
+
+       fd = (int)(uintptr_t)(data);
+       ASSERT(fd != -1);
+
+       do {
+               memset(&rx_data, 0x00, sizeof(espp_service_data_from_client_s));
+               if ((ret = read(fd, &rx_data, sizeof(espp_service_data_from_client_s))) < 0) {
+                       strerror_r(errno, str_error, sizeof(str_error));
+                       LOG_ERROR("failed to read(), fd[%d], err: %s", fd, str_error);
+
+               } else if (ret == sizeof(espp_service_data_from_client_s)) {
+
+                       LOG_DEBUG("<<<<< from fd[%d]: func[%s]", fd, rx_data.func);
+
+                       memset(&tx_data, 0x00, sizeof(espp_service_data_from_server_s));
+
+                       /* TODO: add handler */
+                       tx_data.ret = 0;
+
+                       LOG_DEBUG(">>>>>> to fd[%d]: ret[%d]", fd, tx_data.ret);
+
+                       if (write(fd, &tx_data, sizeof(espp_service_data_from_server_s)) < 0) {
+                               strerror_r(errno, str_error, sizeof(str_error));
+                               LOG_ERROR("failed to write(), fd[%d], err: %s", fd, str_error);
+                       }
+
+                       /* TODO: exit condition from command */
+                       goto exit;
+
+               } else {
+                       LOG_ERROR("failed to read(), fd[%d], read size mismatched: ret[%d], expect size[%zu]",
+                               fd, ret, sizeof(espp_service_data_from_client_s));
+                       goto exit;
+               }
+       } while (1);
+
+exit:
+       LOG_DEBUG("close fd[%d]", fd);
+       close(fd);
+       pthread_exit(NULL);
+}
+
+static void *__listen_thread_func(void *data)
+{
+       espp_service_s *svc = (espp_service_s *)data;
+       int ret;
+       int fd;
+       int client_fd = -1;
+       pthread_attr_t attr;
+       char str_error[MAX_ERROR_LEN] = {'\0',};
+
+       pthread_t work_thread_id;
+
+       ASSERT(svc);
+       ASSERT(svc->fd >= 0);
+
+       ret = pthread_attr_init(&attr);
+       if (ret != 0) {
+               LOG_ERROR("failed to pthread_attr_init(), ret[%d]", ret);
+               goto exit;
+       }
+
+       ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+       if (ret != 0) {
+               LOG_ERROR("failed to pthread_attr_setdetachstate(), ret[%d]", ret);
+               goto exit;
+       }
+
+       fd = svc->fd;
+
+       if (listen(fd, 5)) {
+               strerror_r(errno, str_error, sizeof(str_error));
+               LOG_ERROR("failed to listen(), err: %s", str_error);
+               goto exit;
+       }
+       LOG_INFO("listen for fd[%d] success", fd);
+
+       do {
+               client_fd = accept(fd, NULL, NULL);
+               if (client_fd == -1) {
+                       if (errno == EINVAL) /* this might be for socket close */
+                               goto exit;
+                       strerror_r(errno, str_error, sizeof(str_error));
+                       LOG_ERROR("failed to accept(), err: %s", str_error);
+                       goto exit;
+               }
+               LOG_DEBUG("client_fd[%d]", client_fd);
+
+               if (pthread_create(&work_thread_id, &attr, (void *)__work_thread_func, (void *)(uintptr_t)client_fd)) {
+                       LOG_ERROR("failed to pthread_create(), client_fd[%d]", client_fd);
+                       goto exit;
+               }
+
+       } while (1);
+
+exit:
+       if (client_fd >= 0)
+               close(client_fd);
+
+       LOG_DEBUG("pthread_exit()");
+       pthread_attr_destroy(&attr);
+       pthread_exit(NULL);
+}
+
+static int __create_listener_thread(espp_service_s *svc)
+{
+       ASSERT(svc);
+       ASSERT(svc->fd >= 0);
+
+       if (pthread_create(&svc->thread_id, NULL, (void *)__listen_thread_func, (void *)svc)) {
+               LOG_ERROR("failed to pthread_create()");
+               return -1;
+       }
+
+       LOG_DEBUG("thread_id[0x%x]", (unsigned)svc->thread_id);
+
+       return 0;
+}
+
+int espp_service_init_socket(espp_service_s *svc)
+{
+       int fd;
+       struct sockaddr_un addr_un;
+       char str_error[128] = {'\0',};
+
+       ASSERT(svc);
+
+       fd = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (fd < 0) {
+               strerror_r(errno, str_error, sizeof(str_error));
+               LOG_ERROR("failed to socket(), err: %s", str_error);
+               goto exit;
+       }
+
+       LOG_DEBUG("fd[%d]", fd);
+
+       memset(&addr_un, 0, sizeof(addr_un));
+       addr_un.sun_family = AF_UNIX;
+       strncpy(addr_un.sun_path, ESPP_SERVICE_SOCK, sizeof(addr_un.sun_path));
+
+       if (bind(fd, (struct sockaddr *)&addr_un, sizeof(addr_un))) {
+               int errsv = errno;
+               strerror_r(errsv, str_error, sizeof(str_error));
+               LOG_ERROR("failed to bind(), err: %s", str_error);
+               if (errsv == EADDRINUSE) {
+                       unlink(ESPP_SERVICE_SOCK);
+                       LOG_DEBUG("unlink socket and bind again...");
+                       if (bind(fd, (struct sockaddr *)&addr_un, sizeof(addr_un))) {
+                               strerror_r(errno, str_error, sizeof(str_error));
+                               LOG_ERROR("failed to bind() again, err: %s", str_error);
+                               goto exit;
+                       }
+               } else {
+                       goto exit;
+               }
+       }
+
+       svc->fd = fd;
+       LOG_DEBUG("socket binding success, fd[%d]", svc->fd);
+
+       if (__create_listener_thread(svc) != 0)
+               goto exit;
+
+       return 0;
+
+exit:
+       if (fd >= 0)
+               close(fd);
+
+       return -1;
+}
+
+void espp_service_deinit_socket(espp_service_s *svc)
+{
+       ASSERT(svc);
+
+       if (svc->fd >= 0) {
+               unlink(ESPP_SERVICE_SOCK);
+               shutdown(svc->fd, SHUT_RDWR);
+               close(svc->fd);
+               LOG_DEBUG("close() done, fd[%d]", svc->fd);
+               svc->fd = -1;
+       }
+
+       if (svc->thread_id > 0) {
+               LOG_DEBUG("try to pthread_join(), thread_id[0x%x]", (unsigned)svc->thread_id);
+               pthread_join(svc->thread_id, NULL);
+               LOG_DEBUG("pthread_join() done");
+               svc->thread_id = 0;
+       }
+}
\ No newline at end of file
index fac38601d06a22388839de22b08bbb4a2c9733dc..919c93784042c0738f6a5f51e1fd9fe86cc2ca31 100644 (file)
@@ -1,11 +1,14 @@
 espp_service_sources = [
   'espp_service.c',
+  'espp_service_socket.c',
 ]
+
+thread_dep = dependency('threads')
+
 executable('espp-service',
   espp_service_sources,
   include_directories : [configinc],
-  dependencies : [common_deps],
+  dependencies : [common_deps, thread_dep],
   install: true,
   install_rpath : libdir_path,
   pie : true,