%{_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
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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__ */
+
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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
--- /dev/null
+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',
+)
+
-#subdir('client')
+subdir('client')
subdir('daemon')