client: Add initial client library
authorSangchul Lee <sc11.lee@samsung.com>
Wed, 19 Apr 2023 05:57:32 +0000 (14:57 +0900)
committer이상철/Tizen Platform Lab(SR)/삼성전자 <sc11.lee@samsung.com>
Mon, 24 Apr 2023 05:07:39 +0000 (14:07 +0900)
Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
packaging/espp-service.spec
src/client/espp_service_client.c [new file with mode: 0644]
src/client/espp_service_client.h [new file with mode: 0644]
src/client/espp_service_client_priv.h [new file with mode: 0644]
src/client/espp_service_client_socket.c [new file with mode: 0644]
src/client/meson.build [new file with mode: 0644]
src/meson.build

index 523de2c2bd73bcd189f8d3f155add818eebb1188..7a9e35e1ece66a98e27ea11fc9fcb9b8b0c5daf4 100644 (file)
@@ -67,3 +67,17 @@ install -m0644 %{SOURCE2} %{buildroot}%{_unitdir}/
 %{_bindir}/espp-service
 %{_unitdir}/espp-service.service
 %license LICENSE.APLv2
+
+%files client
+%manifest %{name}.manifest
+%defattr(-,root,root,-)
+%{_lib_dir}/*.so*
+%exclude %{_libdir}/debug/*
+%license LICENSE.APLv2
+
+%files client-devel
+%manifest %{name}.manifest
+%{_lib_dir}/*.so
+%{_libdir}/pkgconfig/espp-service*.pc
+%{_includedir}/*.h
+
diff --git a/src/client/espp_service_client.c b/src/client/espp_service_client.c
new file mode 100644 (file)
index 0000000..db04638
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * 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_client.h"
+#include "espp_service_client_priv.h"
+
+int espp_client_create(espp_h *espp)
+{
+       espp_s *_espp;
+
+       RET_VAL_IF(!espp, ESPP_CLIENT_ERROR_INVALID_PARAMETER, "espp is NULL");
+
+       _espp = g_new0(espp_s, 1);
+
+       g_mutex_init(&_espp->mutex);
+
+       if (espp_service_client_socket_request_create(_espp) != 0) {
+               g_free(_espp);
+               return ESPP_CLIENT_ERROR_INVALID_OPERATION;
+       }
+
+       *espp = _espp;
+
+       LOG_INFO("espp[%p] is created, version[%s]", *espp, ESPP_SVC_VERSION);
+
+       return ESPP_CLIENT_ERROR_NONE;
+}
+
+int espp_client_destroy(espp_h espp)
+{
+       espp_s *_espp = (espp_s *)espp;
+
+       RET_VAL_IF(!espp, ESPP_CLIENT_ERROR_INVALID_PARAMETER, "espp is NULL");
+
+       g_mutex_lock(&_espp->mutex);
+
+       if (espp_service_client_socket_request_destroy(_espp) != 0) {
+               g_mutex_unlock(&_espp->mutex);
+               return ESPP_CLIENT_ERROR_INVALID_OPERATION;
+       }
+
+       g_mutex_unlock(&_espp->mutex);
+       g_mutex_clear(&_espp->mutex);
+
+       LOG_INFO("espp[%p] is destroyed", espp);
+
+       g_free(espp);
+
+       return ESPP_CLIENT_ERROR_NONE;
+}
+
+int espp_client_start(espp_h espp)
+{
+       espp_s *_espp = (espp_s *)espp;
+       g_autoptr(GMutexLocker) locker = NULL;
+
+       RET_VAL_IF(!espp, ESPP_CLIENT_ERROR_INVALID_PARAMETER, "espp is NULL");
+
+       locker = g_mutex_locker_new(&_espp->mutex);
+
+       if (espp_service_client_socket_request_start(_espp) != 0)
+               return ESPP_CLIENT_ERROR_INVALID_OPERATION;
+
+       LOG_INFO("espp[%p] is started", espp);
+
+       return ESPP_CLIENT_ERROR_NONE;
+}
\ No newline at end of file
diff --git a/src/client/espp_service_client.h b/src/client/espp_service_client.h
new file mode 100644 (file)
index 0000000..4c59b7f
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+#ifndef __ESPP_SERVICE_CLIENT_H__
+#define __ESPP_SERVICE_CLIENT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @brief ESPP service client handle type.
+ */
+typedef void *espp_h;
+
+/**
+ * @brief Enumeration for ESPP service client error.
+ */
+typedef enum {
+       ESPP_CLIENT_ERROR_NONE,                   /**< Successful */
+       ESPP_CLIENT_ERROR_INVALID_PARAMETER,      /**< Invalid parameter */
+       ESPP_CLIENT_ERROR_INVALID_OPERATION,      /**< Invalid operation */
+} espp_client_error_e;
+
+/**
+ * @brief Creates an instance of ESPP service client.
+ * @param[out] espp    ESPP service client handle
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #ESPP_CLIENT_ERROR_NONE Successful
+ * @retval #ESPP_CLIENT_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #ESPP_CLIENT_ERROR_INVALID_OPERATION Invalid operation
+ * @see espp_client_destroy()
+ */
+int espp_client_create(espp_h *espp);
+
+/**
+ * @brief Destroys the espp.
+ * @param[in] espp    ESPP service client handle
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #ESPP_CLIENT_ERROR_NONE Successful
+ * @retval #ESPP_CLIENT_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #ESPP_CLIENT_ERROR_INVALID_OPERATION Invalid operation
+ * @see espp_client_create()
+ */
+int espp_client_destroy(espp_h espp);
+
+/**
+ * @brief Starts the espp.
+ * @param[in] espp    ESPP service client handle
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #ESPP_CLIENT_ERROR_NONE Successful
+ * @retval #ESPP_CLIENT_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #ESPP_CLIENT_ERROR_INVALID_OPERATION Invalid operation
+ * @see espp_client_create()
+ */
+int espp_client_start(espp_h espp);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ESPP_SERVICE_CLIENT_H__ */
+
diff --git a/src/client/espp_service_client_priv.h b/src/client/espp_service_client_priv.h
new file mode 100644 (file)
index 0000000..ff82169
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#ifndef __ESPP_SERVICE_CLIENT_PRIVATE_H__
+#define __ESPP_SERVICE_CLIENT_PRIVATE_H__
+
+#include "../common/espp_service_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef USE_DLOG
+#define LOG_TAG "ESPP_SERVICE_CLIENT"
+#endif
+
+typedef struct _espp_s {
+       GMutex mutex;
+       int fd;
+} espp_s;
+
+int espp_service_client_socket_request_create(espp_s *espp);
+int espp_service_client_socket_request_destroy(espp_s *espp);
+int espp_service_client_socket_request_start(espp_s *espp);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ESPP_SERVICE_CLIENT_PRIVATE_H__ */
diff --git a/src/client/espp_service_client_socket.c b/src/client/espp_service_client_socket.c
new file mode 100644 (file)
index 0000000..3944d26
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * 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_client_priv.h"
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#define MAX_CONNECT_RETRY 10
+#define RETRY_CONNECT_INTERVAL_US 300000
+
+#define STRNCPY(x_dst, x_src, x_size) \
+do { \
+       ASSERT(x_dst); \
+       ASSERT(x_src); \
+       ASSERT(x_size > 0); \
+       strncpy(x_dst, x_src, x_size); \
+       x_dst[x_size - 1] = '\0';\
+} while (0) \
+
+#define FILL_SOCKET_MSG_FUNC(x_msg, x_func) \
+do { \
+       memset(&x_msg.func, 0x00, MAX_FUNC_LEN); \
+       STRNCPY(x_msg.func, x_func, MAX_FUNC_LEN); \
+} while (0) \
+
+#define RET_VAL_IF_SERVER_RESULT_ERROR(x_result, x_val) \
+do { \
+       if (x_result.ret != 0) { \
+               LOG_ERROR("failure from server side, result.ret[%d]", x_result.ret); \
+               return x_val; \
+       } \
+} while (0) \
+
+static int get_client_socket_fd(int *fd)
+{
+       int _fd;
+       char str_error[MAX_ERROR_LEN] = {'\0',};
+
+       ASSERT(fd);
+
+       _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);
+               return -1;
+       }
+
+       *fd = _fd;
+
+       LOG_DEBUG("fd[%d]", _fd);
+
+       return 0;
+}
+
+static int connect_socket(int fd)
+{
+       int ret;
+       int retry_count = MAX_CONNECT_RETRY;
+       struct sockaddr_un addr_un;
+       char str_error[MAX_ERROR_LEN] = {'\0',};
+
+       ASSERT(fd >= 0);
+
+       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));
+
+       do {
+               ret = connect(fd, (struct sockaddr *)&addr_un, sizeof(addr_un));
+               if (ret == 0) {
+                       LOG_DEBUG("connected successfully, fd[%d]", fd);
+                       return 0;
+               }
+
+               strerror_r(errno, str_error, sizeof(str_error));
+               LOG_ERROR("[%2d] failed to connect(), fd[%d], sun_path[%s], err: %s",
+                       retry_count, fd, addr_un.sun_path, str_error);
+
+               usleep(RETRY_CONNECT_INTERVAL_US);
+       } while (--retry_count > 0);
+
+       LOG_ERROR("connection timeout[%u us]", MAX_CONNECT_RETRY * RETRY_CONNECT_INTERVAL_US);
+
+       return -1;
+}
+
+static int send_data(int fd, espp_service_data_from_client_s *data, espp_service_data_from_server_s *result)
+{
+       int ret;
+       char str_error[MAX_ERROR_LEN] = {'\0',};
+
+       ASSERT(fd >= 0);
+       ASSERT(data);
+       ASSERT(result);
+
+       if (write(fd, data, sizeof(espp_service_data_from_client_s)) < 0) {
+               strerror_r(errno, str_error, sizeof(str_error));
+               LOG_ERROR("failed to write(), fd[%d], err: %s", fd, str_error);
+               return -1;
+       }
+
+       if ((ret = read(fd, result, sizeof(espp_service_data_from_server_s))) < 0) {
+               strerror_r(errno, str_error, sizeof(str_error));
+               LOG_ERROR("failed to read(), fd[%d], err: %s", fd, str_error);
+               return -1;
+       }
+
+       LOG_DEBUG("fd[%d] func[%s], ret[%d]", fd, data->func, result->ret);
+
+       return 0;
+}
+
+int espp_service_client_socket_request_create(espp_s *espp)
+{
+       int fd = -1;
+       espp_service_data_from_client_s data;
+       espp_service_data_from_server_s result;
+
+       ASSERT(espp);
+
+       if (get_client_socket_fd(&fd) != 0)
+               return -1;
+
+       if (connect_socket(fd) != 0)
+               goto error;
+
+       FILL_SOCKET_MSG_FUNC(data, ESPP_FUNC_CREATE);
+       if (send_data(fd, &data, &result) != 0)
+               goto error;
+       if (result.ret != 0) {
+               LOG_ERROR("failure from server side, result.ret[%d]", result.ret);
+               goto error;
+       }
+
+       LOG_DEBUG("espp[%p], fd[%d]", espp, fd);
+
+       espp->fd = fd;
+
+       return 0;
+
+error:
+       if (fd != -1)
+               close(fd);
+       return -1;
+}
+
+int espp_service_client_socket_request_destroy(espp_s *espp)
+{
+       espp_service_data_from_client_s data;
+       espp_service_data_from_server_s result;
+
+       ASSERT(espp);
+       RET_VAL_IF(espp->fd == -1, -1, "fd is -1");
+
+       FILL_SOCKET_MSG_FUNC(data, ESPP_FUNC_DESTROY);
+       if (send_data(espp->fd, &data, &result) != 0)
+               return -1;
+
+       RET_VAL_IF_SERVER_RESULT_ERROR(result, -1);
+
+       LOG_DEBUG("espp[%p], fd[%d]", espp, espp->fd);
+
+       close(espp->fd);
+       espp->fd = -1;
+
+       return 0;
+}
+
+int espp_service_client_socket_request_start(espp_s *espp)
+{
+       espp_service_data_from_client_s data;
+       espp_service_data_from_server_s result;
+
+       ASSERT(espp);
+       RET_VAL_IF(espp->fd == -1, -1, "fd is -1");
+
+       FILL_SOCKET_MSG_FUNC(data, ESPP_FUNC_START);
+       if (send_data(espp->fd, &data, &result) != 0)
+               return -1;
+
+       RET_VAL_IF_SERVER_RESULT_ERROR(result, -1);
+
+       LOG_DEBUG("espp[%p], fd[%d]", espp, espp->fd);
+
+       return 0;
+}
\ No newline at end of file
diff --git a/src/client/meson.build b/src/client/meson.build
new file mode 100644 (file)
index 0000000..57edd4b
--- /dev/null
@@ -0,0 +1,31 @@
+espp_service_client_headers = files([
+  'espp_service_client.h',
+])
+
+install_headers(espp_service_client_headers)
+
+espp_service_client_deps = []
+
+espp_service_client_sources = files([
+  'espp_service_client.c',
+  'espp_service_client_socket.c',
+])
+
+espp_dep = dependency('esplusplayer', required: true)
+espp_service_client_deps += [espp_dep]
+
+libespp_service_client = library('espp-service-client',
+  espp_service_client_sources,
+  dependencies: common_deps + espp_service_client_deps,
+  include_directories: [configinc, '.'],
+  version: espp_service_version,
+  soversion: version_major,
+  install: true,
+  install_rpath: libdir_path
+)
+
+pkgconfig.generate(libespp_service_client,
+  name: 'espp-service-client',
+  description: 'ESPP service client library',
+)
+
index 610a8ef1e5d28359512f16d2634790e64a47e83a..b0441daae15f0e428d7a4350dc590b308edd7f4a 100644 (file)
@@ -1,2 +1,2 @@
-#subdir('client')
+subdir('client')
 subdir('daemon')