From 12b68bbfeee92d2c9675f07312e013023c402e45 Mon Sep 17 00:00:00 2001 From: "kibak.yoon" Date: Tue, 4 Apr 2017 17:34:07 +0900 Subject: [PATCH 01/16] sensord: change sensord systemd socket files and name - change socket file name from sensord_command.socket to .sensord.socket - change socket file location from /tmp/ to /run/ - remove sensor_event.socket(useless) Change-Id: If855c7a3f4c45778b309c8a932a6da1eb17519ca Signed-off-by: kibak.yoon --- packaging/sensord.service | 3 +-- .../{sensord_command.socket => sensord.socket} | 4 ++-- packaging/sensord.spec | 25 ++++++++++------------ packaging/sensord_event.socket | 13 ----------- src/shared/command_common.h | 3 +-- 5 files changed, 15 insertions(+), 33 deletions(-) rename packaging/{sensord_command.socket => sensord.socket} (68%) delete mode 100644 packaging/sensord_event.socket diff --git a/packaging/sensord.service b/packaging/sensord.service index 031b383..0f2c7f7 100644 --- a/packaging/sensord.service +++ b/packaging/sensord.service @@ -8,8 +8,7 @@ Type=notify SmackProcessLabel=System ExecStart=/usr/bin/sensord MemoryLimit=20M -Sockets=sensord_command.socket -Sockets=sensord_event.socket +Sockets=sensord.socket [Install] WantedBy=multi-user.target diff --git a/packaging/sensord_command.socket b/packaging/sensord.socket similarity index 68% rename from packaging/sensord_command.socket rename to packaging/sensord.socket index 05f8333..31cff8d 100644 --- a/packaging/sensord_command.socket +++ b/packaging/sensord.socket @@ -1,10 +1,10 @@ [Unit] -Description=Sensor command socket +Description=Sensor socket [Socket] SocketUser=sensor SocketGroup=input -ListenStream=/tmp/sensord_command_socket +ListenStream=/run/.sensord.socket SocketMode=0777 PassCredentials=yes Accept=false diff --git a/packaging/sensord.spec b/packaging/sensord.spec index 213cb52..cb86503 100644 --- a/packaging/sensord.spec +++ b/packaging/sensord.spec @@ -6,8 +6,7 @@ Group: System/Sensor Framework License: Apache-2.0 Source0: %{name}-%{version}.tar.gz Source1: sensord.service -Source2: sensord_command.socket -Source3: sensord_event.socket +Source2: sensord.socket BuildRequires: cmake BuildRequires: libattr-devel @@ -80,32 +79,32 @@ with the old build snapshots. This is a temporal solution to handle such cases. %prep %setup -q -MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'` -cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} -DLIBDIR=%{_libdir} \ - -DMAJORVER=${MAJORVER} -DFULLVER=%{version} %build -make %{?jobs:-j%jobs} +MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'` + +%cmake . -DMAJORVER=${MAJORVER} -DFULLVER=%{version} +make %{?_smp_mflags} %install -rm -rf %{buildroot} %make_install mkdir -p %{buildroot}%{_unitdir} install -m 0644 %SOURCE1 %{buildroot}%{_unitdir} install -m 0644 %SOURCE2 %{buildroot}%{_unitdir} -install -m 0644 %SOURCE3 %{buildroot}%{_unitdir} %install_service multi-user.target.wants sensord.service -%install_service sockets.target.wants sensord_event.socket -%install_service sockets.target.wants sensord_command.socket +%install_service sockets.target.wants sensord.socket ln -s libsensor.so.2 %{buildroot}%{_libdir}/libsensor.so.1 %post /sbin/ldconfig +%postun +/sbin/ldconfig + %files %manifest packaging/sensord.manifest %{_libdir}/libsensor.so.* @@ -127,11 +126,9 @@ echo "You need to reinstall %{name}, if you need to keep using the APIs after ui %{_libdir}/libsensor-genuine.so.* %{_bindir}/sensord %{_unitdir}/sensord.service -%{_unitdir}/sensord_command.socket -%{_unitdir}/sensord_event.socket +%{_unitdir}/sensord.socket %{_unitdir}/multi-user.target.wants/sensord.service -%{_unitdir}/sockets.target.wants/sensord_command.socket -%{_unitdir}/sockets.target.wants/sensord_event.socket +%{_unitdir}/sockets.target.wants/sensord.socket %files devel %manifest packaging/sensord.manifest diff --git a/packaging/sensord_event.socket b/packaging/sensord_event.socket deleted file mode 100644 index acd4a1d..0000000 --- a/packaging/sensord_event.socket +++ /dev/null @@ -1,13 +0,0 @@ -[Unit] -Description=Sensor event socket - -[Socket] -SocketUser=sensor -SocketGroup=input -ListenSequentialPacket=/tmp/sensord_event_socket -SocketMode=0777 -PassCredentials=yes -Accept=false -SmackLabelIPIn=* -SmackLabelIPOut=@ -Service=sensord.service diff --git a/src/shared/command_common.h b/src/shared/command_common.h index ccbba3c..c3711ce 100644 --- a/src/shared/command_common.h +++ b/src/shared/command_common.h @@ -24,8 +24,7 @@ #include #include -#define COMMAND_CHANNEL_PATH "/tmp/sensord_command_socket\0" -#define EVENT_CHANNEL_PATH "/tmp/sensord_event_socket\0" +#define SENSOR_CHANNEL_PATH "/run/.sensord.socket" #define MAX_HANDLE 256 #define MAX_HANDLE_REACHED -2 -- 2.7.4 From f8973391fece9e5da3bd916b1687835abb04ce34 Mon Sep 17 00:00:00 2001 From: "kibak.yoon" Date: Tue, 4 Apr 2017 18:02:53 +0900 Subject: [PATCH 02/16] sensorctl: modify sensorctl to fix some issues - prints sensor information with their types - change is_running type from bool to std::atomic - change sensor name from auto_rotation to rotation only - if there are two or more sensors of the same type, you can select them Change-Id: If277104ea324c1ae0da675a6e50ce677a8bbc6c9 Signed-off-by: kibak.yoon --- src/sensorctl/info.cpp | 3 +++ src/sensorctl/mainloop.cpp | 6 +++--- src/sensorctl/mainloop.h | 3 ++- src/sensorctl/sensor_adapter.cpp | 4 ++-- src/sensorctl/sensor_manager.cpp | 2 +- src/sensorctl/test_bench.cpp | 5 +---- src/sensorctl/tester.cpp | 3 ++- 7 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/sensorctl/info.cpp b/src/sensorctl/info.cpp index 6597230..149b98c 100644 --- a/src/sensorctl/info.cpp +++ b/src/sensorctl/info.cpp @@ -50,6 +50,7 @@ bool info_manager::run(int argc, char *argv[]) void info_manager::show_info(sensor_t *sensors, int count) { + sensor_type_t type; sensor_t sensor; char *vendor; char *name; @@ -63,6 +64,7 @@ void info_manager::show_info(sensor_t *sensors, int count) for (int i = 0; i < count; ++i) { sensor = sensors[i]; + sensord_get_type(sensor, &type); name = const_cast(sensord_get_name(sensor)); vendor = const_cast(sensord_get_vendor(sensor)); sensord_get_max_range(sensor, &max_range); @@ -73,6 +75,7 @@ void info_manager::show_info(sensor_t *sensors, int count) sensord_get_max_batch_count(sensor, &max_batch_count); _N("-------sensor[%d] information-------\n", i); + _N("type : %#x\n", type); _N("vendor : %s\n", vendor); _N("name : %s\n", name); _N("min_range : %f\n", min_range); diff --git a/src/sensorctl/mainloop.cpp b/src/sensorctl/mainloop.cpp index 8ea1d4a..00a5772 100644 --- a/src/sensorctl/mainloop.cpp +++ b/src/sensorctl/mainloop.cpp @@ -46,7 +46,7 @@ void mainloop::start_loop(void) return; m_mainloop = g_main_loop_new(NULL, false); - m_running = true; + m_running.store(true); g_main_loop_run(m_mainloop); } @@ -59,11 +59,11 @@ void mainloop::stop_loop(void) g_main_loop_quit(m_mainloop); g_main_loop_unref(m_mainloop); m_mainloop = NULL; - m_running = false; + m_running.store(false); } bool mainloop::is_loop_running(void) { - return m_running; + return m_running.load(); } diff --git a/src/sensorctl/mainloop.h b/src/sensorctl/mainloop.h index 70e3e53..0f550ac 100644 --- a/src/sensorctl/mainloop.h +++ b/src/sensorctl/mainloop.h @@ -21,6 +21,7 @@ #include #include +#include class mainloop { public: @@ -36,5 +37,5 @@ private: bool is_loop_running(void); GMainLoop *m_mainloop; - bool m_running; + std::atomic m_running; }; diff --git a/src/sensorctl/sensor_adapter.cpp b/src/sensorctl/sensor_adapter.cpp index 056b5a6..9ed2b24 100644 --- a/src/sensorctl/sensor_adapter.cpp +++ b/src/sensorctl/sensor_adapter.cpp @@ -92,10 +92,10 @@ bool sensor_adapter::stop(sensor_info info, int handle) { bool ret; - ret = sensord_unregister_event(handle, SENSOR_EVENT(info.type)); + ret = sensord_stop(handle); EXPECT_TRUE(ret); - ret = sensord_stop(handle); + ret = sensord_unregister_event(handle, SENSOR_EVENT(info.type)); EXPECT_TRUE(ret); ret = sensord_disconnect(handle); diff --git a/src/sensorctl/sensor_manager.cpp b/src/sensorctl/sensor_manager.cpp index 25ff923..694d34e 100644 --- a/src/sensorctl/sensor_manager.cpp +++ b/src/sensorctl/sensor_manager.cpp @@ -61,7 +61,7 @@ static struct sensor_info sensor_infos[] = { {HUMAN_PEDOMETER_SENSOR, "pedo"}, {HUMAN_SLEEP_MONITOR_SENSOR, "sleep_monitor"}, - {AUTO_ROTATION_SENSOR, "auto_rotation"}, + {AUTO_ROTATION_SENSOR, "rotation"}, //{AUTO_BRIGHTENESS_SENSOR, "auto_brighteness"}, {MOTION_SENSOR, "motion"}, {CONTEXT_SENSOR, "context"}, diff --git a/src/sensorctl/test_bench.cpp b/src/sensorctl/test_bench.cpp index f675133..191fb0d 100644 --- a/src/sensorctl/test_bench.cpp +++ b/src/sensorctl/test_bench.cpp @@ -163,10 +163,7 @@ void test_bench::show_failures(void) for (unsigned int i = 0; i < results.size(); ++i) { _E("[ FAILED ] "); - _N("%s(%ld) -> %s\n", - results[i].function.c_str(), - results[i].line, - results[i].msg.c_str()); + _N("%s\n", results[i].msg.c_str()); } } diff --git a/src/sensorctl/tester.cpp b/src/sensorctl/tester.cpp index c164a57..1ea034a 100644 --- a/src/sensorctl/tester.cpp +++ b/src/sensorctl/tester.cpp @@ -167,7 +167,8 @@ TESTCASE(skip_manual, sensor_test) if (sensor_adapter::get_count(type) > 1) { _N("There are more than 2 sensors. please enter the index : "); - scanf("%d", &index); + if (scanf("%d", &index) != 1) + return false; } sensor_info info(type, index, interval, latency, powersave, test_cb, NULL); -- 2.7.4 From cc7f933d04c82c0517397b00a74f0fcd25feb1e6 Mon Sep 17 00:00:00 2001 From: "kibak.yoon" Date: Tue, 4 Apr 2017 18:09:50 +0900 Subject: [PATCH 03/16] sensord: clean up cmake configurations - fix typos - use uppercase letters in commands - use CMAKE_LD_LIBS macro to link dl library - the sensord executable binary no longer contains a sensor code Change-Id: I23dbdfea814ef2961eea63e8eec9e85e2a88f9eb Signed-off-by: kibak.yoon --- CMakeLists.txt | 4 ++-- src/server/CMakeLists.txt | 14 ++++++-------- src/shared/CMakeLists.txt | 8 +++----- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c5d9d08..e91c388 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,12 +7,12 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) # Common Options SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -O2 -omit-frame-pointer -std=gnu++0x") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdata-sections -ffunction-sections") -SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-section -Wl,--print-gc-section") +SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections -Wl,--print-gc-sections") MESSAGE("FLAGS: ${CMAKE_CXX_FLAGS}") MESSAGE("FLAGS: ${CMAKE_EXE_LINKER_FLAGS}") # Internal Debugging Options -#add_definitions(-Wall -g -D_DEBUG) +#ADD_DEFINITIONS(-Wall -g -D_DEBUG) # Sub-directory ADD_SUBDIRECTORY(src/shared) diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt index c71bcec..6be6472 100644 --- a/src/server/CMakeLists.txt +++ b/src/server/CMakeLists.txt @@ -6,27 +6,25 @@ SET(DEPENDENTS "glib-2.0 gio-2.0 dlog libsystemd-daemon cynara-client cynara-cre INCLUDE(FindPkgConfig) PKG_CHECK_MODULES(SERVER_PKGS REQUIRED ${DEPENDENTS}) -ADD_SUBDIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/../sensor ${CMAKE_CURRENT_BINARY_DIR}/sensor) ADD_DEFINITIONS(${SENSOR_DEFINITIONS}) -ADD_DEFINITIONS(-DLIBDIR="${LIBDIR}") +ADD_DEFINITIONS(-DLIBDIR="${CMAKE_INSTALL_LIBDIR}") FOREACH(flag ${SERVER_PKGS_CFLAGS}) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flag}") ENDFOREACH(flag) -SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ldl -fPIE") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIE") SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie") INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/src/shared + ${CMAKE_SOURCE_DIR}/src/sensor ${CMAKE_SOURCE_DIR}/src/hal ${CMAKE_CURRENT_SOURCE_DIR} - ${SENSOR_HEADERS} ) FILE(GLOB SERVER_SRCS *.cpp) ADD_EXECUTABLE(${PROJECT_NAME} ${SENSOR_SRCS} ${SERVER_SRCS}) - -TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${SERVER_PKGS_LDFLAGS} "sensord-shared") - -INSTALL(TARGETS ${PROJECT_NAME} DESTINATION bin) +SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${SERVER_PKGS_LDFLAGS} ${CMAKE_DL_LIBS} "sensord-shared") +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/src/shared/CMakeLists.txt b/src/shared/CMakeLists.txt index 69b88ed..eb20325 100644 --- a/src/shared/CMakeLists.txt +++ b/src/shared/CMakeLists.txt @@ -1,7 +1,7 @@ -cmake_minimum_required(VERSION 2.6) -project(sensord-shared CXX) +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(sensord-shared CXX) -SET(DEPENDENTS "dlog") +SET(DEPENDENTS "dlog libsystemd-daemon glib-2.0 gio-2.0") INCLUDE(FindPkgConfig) PKG_CHECK_MODULES(SHARED_PKGS REQUIRED ${DEPENDENTS}) @@ -18,7 +18,5 @@ INCLUDE_DIRECTORIES( FILE(GLOB_RECURSE SRCS *.cpp) ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS}) - TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${SHARED_PKGS_LDFLAGS}) - INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR}) -- 2.7.4 From 834df86f338de3ee2428f1b9aedd4703e194b233 Mon Sep 17 00:00:00 2001 From: "kibak.yoon" Date: Tue, 4 Apr 2017 18:22:21 +0900 Subject: [PATCH 04/16] sensord: clean up command-related types and log-related files - remove sensor_log.cpp - rename command_common.h to command_types.h Change-Id: I01635838c0a11f466b183b3766ee013a19dee6b8 Signed-off-by: kibak.yoon --- include/sensor_types.h | 2 + src/sensorctl/tester.cpp | 12 +-- src/shared/command_common.h | 192 -------------------------------------------- src/shared/command_types.h | 116 ++++++++++++++++++++++++++ src/shared/sensor_log.cpp | 89 -------------------- src/shared/sensor_log.h | 117 ++++++--------------------- 6 files changed, 150 insertions(+), 378 deletions(-) delete mode 100644 src/shared/command_common.h create mode 100644 src/shared/command_types.h delete mode 100644 src/shared/sensor_log.cpp diff --git a/include/sensor_types.h b/include/sensor_types.h index c244943..5062062 100644 --- a/include/sensor_types.h +++ b/include/sensor_types.h @@ -225,6 +225,8 @@ enum poll_interval_t { POLL_MAX_HZ_MS = 255000, }; +#define DEFAULT_INTERVAL POLL_10HZ_MS + enum sensor_interval_t { SENSOR_INTERVAL_FASTEST = POLL_100HZ_MS, SENSOR_INTERVAL_NORMAL = POLL_5HZ_MS, diff --git a/src/sensorctl/tester.cpp b/src/sensorctl/tester.cpp index 1ea034a..4ac906f 100644 --- a/src/sensorctl/tester.cpp +++ b/src/sensorctl/tester.cpp @@ -33,9 +33,9 @@ #define TESTER_ARGC 3 /* e.g. {sensorctl, test, accelerometer} */ #define MAX_COUNT 999999 -#define DEFAULT_INTERVAL 100 -#define DEFAULT_LATENCY 0 -#define DEFAULT_POWERSAVE_OPTION SENSOR_OPTION_ALWAYS_ON +#define TEST_DEFAULT_INTERVAL 100 +#define TEST_DEFAULT_LATENCY 0 +#define TEST_DEFAULT_POWERSAVE_OPTION SENSOR_OPTION_ALWAYS_ON static sensor_type_t type; static int interval; @@ -94,9 +94,9 @@ bool tester_manager::setup_manual(int argc, char *argv[]) type = get_sensor_type(argv[2]); RETVM_IF(type == UNKNOWN_SENSOR, false, "Invalid argument\n"); - interval = DEFAULT_INTERVAL; - latency = DEFAULT_LATENCY; - powersave = DEFAULT_POWERSAVE_OPTION; + interval = TEST_DEFAULT_INTERVAL; + latency = TEST_DEFAULT_LATENCY; + powersave = TEST_DEFAULT_POWERSAVE_OPTION; event_count = 0; if (argc >= TESTER_ARGC + 1) diff --git a/src/shared/command_common.h b/src/shared/command_common.h deleted file mode 100644 index c3711ce..0000000 --- a/src/shared/command_common.h +++ /dev/null @@ -1,192 +0,0 @@ -/* - * sensord - * - * Copyright (c) 2016 Samsung Electronics Co., Ltd. - * - * 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 _COMMAND_COMMON_H_ -#define _COMMAND_COMMON_H_ - -#include -#include -#include - -#define SENSOR_CHANNEL_PATH "/run/.sensord.socket" - -#define MAX_HANDLE 256 -#define MAX_HANDLE_REACHED -2 - -enum packet_type_t { - CMD_DONE = -1, - CMD_NONE = 0, - CMD_GET_ID, - CMD_GET_SENSOR_LIST, - CMD_HELLO, - CMD_BYEBYE, - CMD_START, - CMD_STOP, - CMD_REG, - CMD_UNREG, - CMD_SET_PAUSE_POLICY, - CMD_SET_BATCH, - CMD_UNSET_BATCH, - CMD_GET_DATA, - CMD_SET_ATTRIBUTE_INT, - CMD_SET_ATTRIBUTE_STR, - CMD_FLUSH, - CMD_CNT, -}; - -enum ext_packet_type_t { - CMD_EXT_DONE = -1, - CMD_EXT_NONE = 0, - CMD_EXT_GET_ID, - CMD_EXT_CONNECT, - CMD_EXT_DISCONNECT, - CMD_EXT_POST, - CMD_EXT_CNT, -}; - -typedef struct { - char name[NAME_MAX]; -} cmd_get_id_t; - -typedef struct { -} cmd_get_sensor_list_t; - -typedef struct { - int client_id; - sensor_id_t sensor; -} cmd_hello_t; - -typedef struct { -} cmd_byebye_t; - -typedef struct { - unsigned int type; -} cmd_get_data_t; - -typedef struct { - long value; -} cmd_done_t; - -typedef struct { - int client_id; -} cmd_get_id_done_t; - -typedef struct { - int sensor_cnt; - char data[0]; -} cmd_get_sensor_list_done_t; - -typedef struct { - int state; - sensor_data_t base_data; -} cmd_get_data_done_t; - -typedef struct { -} cmd_start_t; - -typedef struct { -} cmd_stop_t; - -typedef struct { - unsigned int event_type; -} cmd_reg_t; - -typedef struct { - unsigned int event_type; -} cmd_unreg_t; - -typedef struct { - unsigned int interval; - unsigned int latency; -} cmd_set_batch_t; - -typedef struct { -} cmd_unset_batch_t; - -typedef struct { - int pause_policy; -} cmd_set_pause_policy_t; - -typedef struct { - int attribute; - int value; -} cmd_set_attribute_int_t; - -typedef struct { - int attribute; - int len; - char value[0]; -} cmd_set_attribute_str_t; - -typedef struct { -} cmd_flush_t; - -typedef struct { - char name[NAME_MAX]; -} cmd_ext_get_id_t; - -typedef struct { - int client_id; - char key[NAME_MAX]; -} cmd_ext_connect_t; - -typedef struct { -} cmd_ext_disconnect_t; - -typedef struct { - unsigned long long timestamp; - int data_cnt; - float data[0]; -} cmd_ext_post_t; - -typedef struct { - long value; -} cmd_ext_done_t; - -typedef struct { - int client_id; -} cmd_ext_get_id_done_t; - -typedef struct { - sensor_id_t sensor_id; -} cmd_ext_connect_done_t; - -#define CHANNEL_MAGIC_NUM 0xCAFECAFE - -typedef struct { - unsigned int magic; - int client_id; -} channel_ready_t; - -typedef struct external_command_header_t { - sensor_id_t sensor_id; - int command_len; -} external_command_header_t; - -typedef struct external_command_t { - external_command_header_t header; - std::vector command; -} external_command_t; - -typedef void *(*cmd_func_t)(void *data, void *cb_data); - -#define COMMAND_LEN_MAX (10*1024) -#define POST_DATA_LEN_MAX (10*1024) - -#endif /* _COMMAND_COMMON_H_ */ diff --git a/src/shared/command_types.h b/src/shared/command_types.h new file mode 100644 index 0000000..81d4a21 --- /dev/null +++ b/src/shared/command_types.h @@ -0,0 +1,116 @@ +/* + * sensord + * + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * 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 __COMMAND_TYPES_H__ +#define __COMMAND_TYPES_H__ + +#include +#include "sensor_info.h" + +#define SENSOR_CHANNEL_PATH "/run/.sensord.socket" +#define MAX_BUF_SIZE 4096 + +/* TODO: OOP - create serializer interface */ +enum cmd_type_e { + CMD_DONE = -1, + CMD_NONE = 0, + + /* Manager */ + CMD_MANAGER_SENSOR_LIST, + + /* Listener */ + CMD_LISTENER_EVENT, + CMD_LISTENER_ACC_EVENT, + CMD_LISTENER_CONNECT, + CMD_LISTENER_DISCONNECT, + CMD_LISTENER_START, + CMD_LISTENER_STOP, + CMD_LISTENER_ATTR_INT, + CMD_LISTENER_ATTR_STR, + CMD_LISTENER_GET_DATA, + + /* Provider(Dyanmic/External sensor) */ + CMD_PROVIDER_CMD_EVENT, + CMD_PROVIDER_CONNECT, + CMD_PROVIDER_DISCONNECT, + CMD_PROVIDER_POST, + + CMD_CNT, +}; + +typedef struct { + int sensor_cnt; + char data[0]; +} cmd_manager_sensor_list_t; + +typedef struct { + int listener_id; + char sensor[NAME_MAX]; +} cmd_listener_connect_t; + +typedef struct { + int listener_id; +} cmd_listener_disconnect_t; + +typedef struct { + int listener_id; +} cmd_listener_start_t; + +typedef struct { + int listener_id; +} cmd_listener_stop_t; + +typedef struct { + int listener_id; + int attribute; + int value; +} cmd_listener_attr_int_t; + +typedef struct { + int listener_id; + int attribute; + int len; + char value[0]; +} cmd_listener_attr_str_t; + +typedef struct { + int listener_id; + int len; + char data[0]; +} cmd_listener_get_data_t; + +typedef struct { + int provider_id; + int sensor_id; + char sensor[NAME_MAX]; + char s_info[0]; +} cmd_provider_connect_t; + +typedef struct { + int provider_id; + char sensor[NAME_MAX]; +} cmd_provider_disconnect_t; + +typedef struct { + int provider_id; + char sensor[NAME_MAX]; + sensorhub_data_t base_data; +} cmd_provider_post_t; + +#endif /* __COMMAND_TYPES_H__ */ diff --git a/src/shared/sensor_log.cpp b/src/shared/sensor_log.cpp deleted file mode 100644 index f657883..0000000 --- a/src/shared/sensor_log.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * sensord - * - * Copyright (c) 2013 Samsung Electronics Co., Ltd. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PATH_MAX 256 - -#if defined(_DEBUG) -bool get_proc_name(pid_t pid, char *process_name) -{ - FILE *fp; - char buf[NAME_MAX]; - char filename[PATH_MAX]; - - sprintf(filename, "/proc/%d/stat", pid); - fp = fopen(filename, "r"); - - if (fp == NULL) - return false; - - if (fscanf(fp, "%*s (%[^)]", buf) < 1) { - fclose(fp); - return false; - } - - strncpy(process_name, buf, NAME_MAX-1); - process_name[NAME_MAX-1] = '\0'; - fclose(fp); - - return true; -} -#else -bool get_proc_name(pid_t pid, char *process_name) -{ - char buf[NAME_MAX]; - - if (snprintf(buf, sizeof(buf), "%d process", pid) < 1) { - return false; - } - - strncpy(process_name, buf, NAME_MAX-1); - process_name[NAME_MAX-1] = '\0'; - - return true; -} -#endif - -const char* get_client_name(void) -{ - const int pid_string_size = 10; - static pid_t pid = -1; - static char client_name[NAME_MAX + pid_string_size]; - - char proc_name[NAME_MAX]; - - if (pid == -1) - { - pid = getpid(); - get_proc_name(pid, proc_name); - snprintf(client_name, sizeof(client_name), "%s(%d)", proc_name, pid); - } - - return client_name; -} diff --git a/src/shared/sensor_log.h b/src/shared/sensor_log.h index 22d1d7d..f2e0d49 100644 --- a/src/shared/sensor_log.h +++ b/src/shared/sensor_log.h @@ -17,36 +17,29 @@ * */ -#ifndef _SENSOR_LOG_H_ -#define _SENSOR_LOG_H_ +#ifndef __SENSOR_LOG_H__ +#define __SENSOR_LOG_H__ #include #include -#define MICROSECONDS(tv) ((tv.tv_sec * 1000000ll) + tv.tv_usec) - #ifdef LOG_TAG #undef LOG_TAG #endif #define LOG_TAG "SENSOR" -#define LOG_DUMP(fp, fmt, arg...) do { if (fp) fprintf(fp, fmt, ##arg); else _E(fmt, ##arg); } while (0) - -#ifdef _DEBUG -#define DBG SLOGD -#else -#define DBG(...) do {} while (0) -#endif - -#define ERR SLOGE -#define WARN SLOGW -#define INFO SLOGI -#define _E ERR -#define _W WARN -#define _I INFO -#define _D DBG +/* Logging and Error Handling */ +#define _I SLOGI +#define _D SLOGD +#define _W SLOGW +#define _E SLOGE +#define _SI SECURE_SLOGI +#define _SD SECURE_SLOGD +#define _SW SECURE_SLOGW +#define _SE SECURE_SLOGE -#define _ERRNO(errno, tag, fmt, arg...) do { \ +#define _ERRNO(errno, tag, fmt, arg...) \ + do { \ char buf[1024]; \ char *error = strerror_r(errno, buf, 1024); \ if (!error) { \ @@ -56,80 +49,22 @@ tag(fmt" (%s[%d])", ##arg, error, errno); \ } while (0) -#if defined(_DEBUG) -# define warn_if(expr, fmt, arg...) do { \ - if (expr) { \ - _D("(%s) -> " fmt, #expr, ##arg); \ - } \ - } while (0) -# define ret_if(expr) do { \ - if (expr) { \ - _D("(%s) -> %s() return", #expr, __FUNCTION__); \ - return; \ - } \ - } while (0) -# define retv_if(expr, val) do { \ - if (expr) { \ - _D("(%s) -> %s() return", #expr, __FUNCTION__); \ - return (val); \ - } \ - } while (0) -# define retm_if(expr, fmt, arg...) do { \ - if (expr) { \ - _E(fmt, ##arg); \ - _D("(%s) -> %s() return", #expr, __FUNCTION__); \ - return; \ - } \ - } while (0) -# define retvm_if(expr, val, fmt, arg...) do { \ - if (expr) { \ - _E(fmt, ##arg); \ - _D("(%s) -> %s() return", #expr, __FUNCTION__); \ - return (val); \ - } \ - } while (0) +#define warn_if(expr, fmt, arg...) \ + do { if (expr) { _E(fmt, ##arg); } } while (0) -#else -# define warn_if(expr, fmt, arg...) do { \ - if (expr) { \ - _E(fmt, ##arg); \ - } \ - } while (0) -# define ret_if(expr) do { \ - if (expr) { \ - return; \ - } \ - } while (0) -# define retv_if(expr, val) do { \ - if (expr) { \ - return (val); \ - } \ - } while (0) -# define retm_if(expr, fmt, arg...) do { \ - if (expr) { \ - _E(fmt, ##arg); \ - return; \ - } \ - } while (0) -# define retvm_if(expr, val, fmt, arg...) do { \ - if (expr) { \ - _E(fmt, ##arg); \ - return (val); \ - } \ - } while (0) +#define ret_if(expr) \ + do { if (expr) { return; } } while (0) -#endif +#define retv_if(expr, val) \ + do { if (expr) { return (val); } } while (0) -#ifdef __cplusplus -extern "C" -{ -#endif +#define retm_if(expr, fmt, arg...) \ + do { if (expr) { _E(fmt, ##arg); return; } } while (0) -const char* get_client_name(void); -bool get_proc_name(pid_t pid, char *process_name); +#define retvm_if(expr, val, fmt, arg...) \ + do { if (expr) { _E(fmt, ##arg); return (val); } } while (0) -#ifdef __cplusplus -} -#endif +#define LOG_DUMP(fp, fmt, arg...) \ + do { if (fp) fprintf(fp, fmt, ##arg); else _E(fmt, ##arg); } while (0) -#endif /* _SENSOR_LOG_H_ */ +#endif /* __SENSOR_LOG_H__ */ -- 2.7.4 From 6549a6d6f6503fd384d0e61eaa27f70a9b2f4f72 Mon Sep 17 00:00:00 2001 From: "kibak.yoon" Date: Tue, 4 Apr 2017 18:43:36 +0900 Subject: [PATCH 05/16] sensord: ipc: add socket class - socket class is a wrapper class of unix domain socket - supported socket types : stream_socket, seqpacket_socket - TC : $ sensorctl test auto ipc_socket - [PASS] sensor_ipc_socket.socket_p_0 - [PASS] sensor_ipc_socket.socket_p_10 - [PASS] sensor_ipc_socket.socket_p_1000 Change-Id: I2cb7fcb360d4a9a0c87c77d3e2b39c2bb0c06380 Signed-off-by: kibak.yoon --- src/sensorctl/testcase/unit_socket.cpp | 202 +++++++++++++++ src/shared/seqpacket_socket.cpp | 95 +++++++ src/shared/seqpacket_socket.h | 42 +++ src/shared/socket.cpp | 459 +++++++++++++++++++++++++++++++++ src/shared/socket.h | 83 ++++++ src/shared/stream_socket.cpp | 102 ++++++++ src/shared/stream_socket.h | 41 +++ 7 files changed, 1024 insertions(+) create mode 100644 src/sensorctl/testcase/unit_socket.cpp create mode 100644 src/shared/seqpacket_socket.cpp create mode 100644 src/shared/seqpacket_socket.h create mode 100644 src/shared/socket.cpp create mode 100644 src/shared/socket.h create mode 100644 src/shared/stream_socket.cpp create mode 100644 src/shared/stream_socket.h diff --git a/src/sensorctl/testcase/unit_socket.cpp b/src/sensorctl/testcase/unit_socket.cpp new file mode 100644 index 0000000..3b15b5a --- /dev/null +++ b/src/sensorctl/testcase/unit_socket.cpp @@ -0,0 +1,202 @@ +/* + * sensorctl + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 +#include +#include + +#include "shared/socket.h" +#include "shared/stream_socket.h" + +#include "log.h" +#include "test_bench.h" + +using namespace ipc; + +#define MAX_BUF_SIZE 4096 +#define TEST_PATH "/run/.sensord_test.socket" + +typedef bool (*process_func_t)(const char *msg, int size, int count); + +static pid_t run_process(process_func_t func, const char *msg, int size, int count) +{ + pid_t pid = fork(); + if (pid < 0) + return -1; + + if (pid == 0) { + if (!func(msg, size, count)) + _E("Failed to run process\n"); + exit(0); + } + + return pid; +} + +/* Socket */ +static bool run_socket_echo_server(const char *msg, int size, int count) +{ + char buf[MAX_BUF_SIZE] = {0, }; + bool ret = false; + int send_size = 0; + int recv_size = 0; + int recv_count = 0; + int send_count = 0; + int total_recv_size = 0; + int total_send_size = 0; + stream_socket accept_sock; + stream_socket client_sock; + + accept_sock.create(TEST_PATH); + accept_sock.set_blocking_mode(true); + accept_sock.bind(); + accept_sock.listen(10); + accept_sock.accept(client_sock); + + /* receive message */ + while (recv_count++ < count) { + recv_size = client_sock.recv(&buf, size); + total_recv_size += recv_size; + } + ASSERT_EQ(total_recv_size, (size * count)); + + usleep(10000); + /* echo message */ + while (send_count++ < count) { + send_size = client_sock.send(buf, size); + total_send_size += send_size; + } + ASSERT_EQ(total_send_size, (size * count)); + + ret = strncmp(buf, msg, size); + ASSERT_EQ(ret, 0); + + accept_sock.close(); + client_sock.close(); + + return true; +} + +static bool run_socket_client(const char *msg, int size, int count) +{ + char buf[MAX_BUF_SIZE] = {0, }; + bool ret = false; + int send_size = 0; + int recv_size = 0; + int send_count = 0; + int recv_count = 0; + int total_recv_size = 0; + int total_send_size = 0; + stream_socket sock; + + usleep(100000); + + sock.create(TEST_PATH); + sock.set_blocking_mode(true); + sock.connect(); + + while (send_count++ < count) { + send_size = sock.send(msg, size); + total_send_size += send_size; + } + + ASSERT_EQ(total_send_size, (size * count)); + + while (recv_count++ < count) { + recv_size = sock.recv(&buf, size); + total_recv_size += recv_size; + } + + ASSERT_EQ(total_recv_size, (size * count)); + + ret = strncmp(buf, msg, size); + ASSERT_EQ(ret, 0); + + sock.close(); + + usleep(100000); + + return true; +} + +/** + * @brief Test socket class with simple message + * @details 1. connect socket and listen event by socket + * 2. send/recv "TEST" text by using echo server + * 3. check "TEST" message + * @remarks we can test only regular socket, not systemd-based socket. + */ +TESTCASE(sensor_ipc_socket, socket_p_0) +{ + const char *msg = "TEST"; + int size = 4; + int count = 1; + + pid_t pid = run_process(run_socket_echo_server, msg, size, count); + EXPECT_GE(pid, 0); + + bool ret = run_socket_client(msg, size, count); + ASSERT_TRUE(ret); + + return true; +} + +/** + * @brief Test socket class with 40K message + * @details 1. connect socket and listen event by socket + * 2. send/recv 40960 bytes(4096 bytes * 10) by using echo server + * 3. check total size + * @remarks we can test only regular socket, not systemd-based socket. + */ +TESTCASE(sensor_ipc_socket, socket_p_10) +{ + const char msg[MAX_BUF_SIZE] = {1, }; + int size = MAX_BUF_SIZE; + int count = 10; + + pid_t pid = run_process(run_socket_echo_server, msg, size, count); + EXPECT_GE(pid, 0); + + bool ret = run_socket_client(msg, size, count); + ASSERT_TRUE(ret); + + return true; +} + +/** + * @brief Test socket class with 4M message + * @details 1. connect socket and listen event by socket + * 2. send/recv 4096000 bytes(4096 bytes * 1000) by using echo server + * 3. check total size + * @remarks we can test only regular socket, not systemd-based socket. + */ +TESTCASE(sensor_ipc_socket, socket_p_1000) +{ + const char msg[MAX_BUF_SIZE] = {1, }; + int size = MAX_BUF_SIZE; + int count = 1000; + + pid_t pid = run_process(run_socket_echo_server, msg, size, count); + EXPECT_GE(pid, 0); + + bool ret = run_socket_client(msg, size, count); + ASSERT_TRUE(ret); + + return true; +} \ No newline at end of file diff --git a/src/shared/seqpacket_socket.cpp b/src/shared/seqpacket_socket.cpp new file mode 100644 index 0000000..ef6e01b --- /dev/null +++ b/src/shared/seqpacket_socket.cpp @@ -0,0 +1,95 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 "seqpacket_socket.h" + +#include +#include + +#include "sensor_log.h" + +using namespace ipc; + +seqpacket_socket::seqpacket_socket() +: socket() +{ +} + +seqpacket_socket::~seqpacket_socket() +{ +} + +bool seqpacket_socket::create(const std::string &path) +{ + return socket::create_by_type(path, SOCK_SEQPACKET); +} + +ssize_t seqpacket_socket::on_send(const void *buffer, size_t size) const +{ + ssize_t err, len; + + do { + len = ::send(socket::get_fd(), + reinterpret_cast(buffer), + size, + socket::get_mode()); + + err = len < 0 ? errno : 0; + } while (err == EINTR); + + if (err) { + _ERRNO(errno, _E, "Failed to send(%d, %#x, %d) = %d", + socket::get_fd(), buffer, size, len); + } + + return err == 0 ? len : -err; +} + +ssize_t seqpacket_socket::on_recv(void *buffer, size_t size) const +{ + ssize_t err, len; + + do { + len = ::recv(socket::get_fd(), + reinterpret_cast(buffer), + size, + socket::get_mode()); + + if (len > 0) { + err = 0; + } else if (len == 0) { + _E("Failed to recv(%d, %#p , %d) = %d, because the peer performed shutdown!", + socket::get_fd(), buffer, size, len); + err = 1; + } else { + err = errno; + } + } while (err == EINTR); + + if ((err == EAGAIN) || (err == EWOULDBLOCK)) + return 0; + + if (err) { + _ERRNO(errno, _E, "Failed to recv(%d, %#x, %d) = %d", + socket::get_fd(), buffer, size, len); + } + + return err == 0 ? len : -err; +} + diff --git a/src/shared/seqpacket_socket.h b/src/shared/seqpacket_socket.h new file mode 100644 index 0000000..5614903 --- /dev/null +++ b/src/shared/seqpacket_socket.h @@ -0,0 +1,42 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 __SEQPACKET_SOCKET_H__ +#define __SEQPACKET_SOCKET_H__ + +#include "socket.h" + +namespace ipc { + +class seqpacket_socket : public socket { +public: + seqpacket_socket(); + ~seqpacket_socket(); + + bool create(const std::string &path); + +private: + ssize_t on_send(const void *buffer, size_t size) const; + ssize_t on_recv(void *buffer, size_t size) const; + +}; + +} + +#endif /* __SEQPACKET_SOCKET_H__ */ diff --git a/src/shared/socket.cpp b/src/shared/socket.cpp new file mode 100644 index 0000000..239e554 --- /dev/null +++ b/src/shared/socket.cpp @@ -0,0 +1,459 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 "socket.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "sensor_log.h" + +using namespace ipc; + +static bool set_close_on_exec(int fd) +{ + if (::fcntl(fd, F_SETFL, FD_CLOEXEC) == -1) + return false; + + return true; +} + +static int create_systemd_socket(const std::string &path, int type) +{ + int n; + int listening; + + listening = (type == SOCK_STREAM) ? 1 : -1; + + n = sd_listen_fds(0); + retvm_if(n < 0, -EPERM, "Failed to listen fds from systemd"); + + for (int fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; ++fd) { + if (sd_is_socket_unix(fd, type, listening, path.c_str(), 0) > 0) { + set_close_on_exec(fd); + return fd; + } + } + + return -EPERM; +} + +static int create_unix_socket(int type) +{ + int sock_fd = ::socket(AF_UNIX, type, 0); + + if (sock_fd < 0) { + _ERRNO(errno, _E, "Failed to create socket"); + return -EPERM; + } + + set_close_on_exec(sock_fd); + + int optval = 1; + if (::setsockopt(sock_fd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) < 0) { + _ERRNO(errno, _E, "Failed to create socket[%d]", sock_fd); + ::close(sock_fd); + return -EPERM; + } + + return sock_fd; +} + +static bool select_fds(int fd, fd_set *read_fds, fd_set *write_fds, const int timeout) +{ + struct timeval tv; + int err; + + tv.tv_sec = timeout; + tv.tv_usec = 0; + + while (true) { + err = ::select(fd + 1, read_fds, write_fds, NULL, &tv); + if (err <= 0) + return false; + + if (read_fds && FD_ISSET(fd, read_fds)) + break; + if (write_fds && FD_ISSET(fd, write_fds)) + break; + } + + return true; +} + +socket::socket() +: m_sock_fd(-1) +, m_mode(MSG_DONTWAIT | MSG_NOSIGNAL) +, m_listening(false) +{ +} + +socket::socket(int sock_fd) +: m_sock_fd(sock_fd) +, m_mode(MSG_DONTWAIT | MSG_NOSIGNAL) +, m_listening(false) +{ +} + +socket::socket(const socket &sock) +: m_sock_fd(-1) +, m_mode(MSG_DONTWAIT | MSG_NOSIGNAL) +, m_listening(false) +{ + if (this == &sock) + return; + + m_sock_fd = sock.m_sock_fd; + m_mode = sock.m_mode; + m_listening.store(sock.m_listening); +} + +socket::~socket() +{ + close(); +} + +bool socket::connect(void) +{ + const int TIMEOUT = 3; + sockaddr_un addr; + fd_set write_fds; + FD_ZERO(&write_fds); + FD_SET(m_sock_fd, &write_fds); + + retvm_if(m_path.size() >= sizeof(sockaddr_un::sun_path), false, + "Failed to create socket[%s]", m_path.c_str()); + + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, m_path.c_str(), sizeof(sockaddr_un::sun_path)); + addr.sun_path[m_path.size()] = '\0'; + + if (::connect(m_sock_fd, + reinterpret_cast(&addr), + sizeof(struct sockaddr_un)) < 0) { + _ERRNO(errno, _E, "Failed to connect() for socket[%d]", m_sock_fd); + close(); + return false; + } + + if (!select_fds(m_sock_fd, NULL, &write_fds, TIMEOUT)) { + _E("Failed to select for socket[%d]", m_sock_fd); + close(); + return false; + } + + if (!has_connected()) { + close(); + return false; + } + + _D("Connected[%d]", m_sock_fd); + + return true; +} + +bool socket::bind(void) +{ + sockaddr_un addr; + int file_mode; + + retvm_if(m_path.size() >= sizeof(sockaddr_un::sun_path), false, + "Failed to create socket[%s]", m_path.c_str()); + retv_if(m_listening.load(), true); + + if (!access(m_path.c_str(), F_OK)) + unlink(m_path.c_str()); + + addr.sun_family = AF_UNIX; + ::strncpy(addr.sun_path, m_path.c_str(), sizeof(sockaddr_un::sun_path)); + addr.sun_path[m_path.size()] = '\0'; + + if (::bind(m_sock_fd, + reinterpret_cast(&addr), + sizeof(struct sockaddr_un)) < 0) { + _ERRNO(errno, _E, "Failed to bind for socket[%d]", m_sock_fd); + close(); + return false; + } + + /* TODO: Is this really necessary? */ + file_mode = (S_IRWXU | S_IRWXG | S_IRWXO); + if (chmod(m_path.c_str(), file_mode) < 0) { + _ERRNO(errno, _E, "Failed to create socket[%d]", m_sock_fd); + close(); + return false; + } + + _D("Bound to path[%d, %s]", m_sock_fd, m_path.c_str()); + + return true; +} + +bool socket::listen(const int max_connections) +{ + retv_if(m_listening.load(), true); + + if (::listen(m_sock_fd, max_connections) < 0) { + _ERRNO(errno, _E, "Failed to listen() for socket[%d]", m_sock_fd); + close(); + return false; + } + + m_listening.store(true); + + _D("Listened[%d]", m_sock_fd); + + return true; +} + +bool socket::accept(socket &client_sock) +{ + int fd; + fd_set read_fds; + FD_ZERO(&read_fds); + FD_SET(m_sock_fd, &read_fds); + + fd = ::accept(m_sock_fd, NULL, NULL); + + if (fd < 0) { + _ERRNO(errno, _E, "Failed to accept[%d]", m_sock_fd); + return false; + } + + set_close_on_exec(fd); + client_sock.set_fd(fd); + /* TODO : socket type should be adjusted here */ + + _D("Accepted[%d, %d]", m_sock_fd, fd); + + return true; +} + +bool socket::close(void) +{ + retv_if(m_sock_fd < 0, false); + + if (::close(m_sock_fd) < 0) { + _ERRNO(errno, _E, "Failed to close socket[%d]", m_sock_fd); + return false; + } + + _D("Closed[%d]", m_sock_fd); + + m_sock_fd = -1; + m_listening.store(false); + + return true; +} + +int socket::get_fd(void) const +{ + return m_sock_fd; +} + +void socket::set_fd(int sock_fd) +{ + m_sock_fd = sock_fd; +} + +int socket::get_mode(void) const +{ + return m_mode; +} + +bool socket::set_mode(int mode) +{ + /* TODO : implement send/recv message mode */ + return true; +} + +bool socket::create(const std::string &path) +{ + return false; +} + +ssize_t socket::send(const void *buffer, size_t size, bool select) const +{ + if (select) { + const int TIMEOUT = 1; + fd_set write_fds; + FD_ZERO(&write_fds); + FD_SET(m_sock_fd, &write_fds); + + if (!select_fds(m_sock_fd, NULL, &write_fds, TIMEOUT)) { + _E("Failed to send message(timeout)"); + return 0; + } + } + + return on_send(buffer, size); +} + +ssize_t socket::recv(void* buffer, size_t size, bool select) const +{ + /* WARNING: if select() is called here, it affects performance */ + return on_recv(buffer, size); +} + +bool socket::create_by_type(const std::string &path, int type) +{ + m_sock_fd = ::create_systemd_socket(path, type); + if (m_sock_fd < 0) { + _D("Creating the UDS instead of systemd socket.."); + m_sock_fd = create_unix_socket(type); + } else { + m_listening.store(true); + } + + retvm_if((m_sock_fd < 0), false, "Failed to create socket"); + + /* non-blocking mode */ + retvm_if(!set_blocking_mode(false), false, "Failed to set non-blocking mode"); + /* recv timeout */ + retvm_if(!set_recv_timeout(1), false, "Failed to set timeout"); + /* TODO */ + /*retvm_if(!set_reuse_addr(), false, "Failed to reuse address"); */ + + _D("Created[%d]", m_sock_fd); + + m_path = path; + + return true; +} + +int socket::get_sock_type(void) +{ + socklen_t opt_len; + int sock_type; + opt_len = sizeof(sock_type); + + retvm_if(m_sock_fd < 0, false, "Invalid socket[%d]", m_sock_fd); + + if (getsockopt(m_sock_fd, SOL_SOCKET, SO_TYPE, &sock_type, &opt_len) < 0) { + _ERRNO(errno, _E, "Failed to getsockopt from socket[%d]", m_sock_fd); + return false; + } + + return sock_type; +} + +bool socket::set_recv_timeout(int sec) +{ + struct timeval timeout = {sec, 0}; + + retvm_if(m_sock_fd < 0, false, "Invalid socket[%d]", m_sock_fd); + + if (setsockopt(m_sock_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) { + _ERRNO(errno, _E, "Failed to setsockopt[%d]", m_sock_fd); + return false; + } + + return true; +} + +bool socket::set_sock_type(int type) +{ + socklen_t opt_len; + int sock_type; + opt_len = sizeof(sock_type); + + retvm_if(m_sock_fd < 0, false, "Invalid socket[%d]", m_sock_fd); + + if (setsockopt(m_sock_fd, SOL_SOCKET, SO_TYPE, &sock_type, opt_len) < 0) { + _ERRNO(errno, _E, "Failed to setsockopt[%d]", m_sock_fd); + return false; + } + + return true; +} + +bool socket::set_blocking_mode(bool blocking) +{ + int flags; + + flags = fcntl(m_sock_fd, F_GETFL); + retvm_if(flags == -1, false, "Failed to fcntl(F_GETFL)[%d]", m_sock_fd); + + flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK); + + flags = fcntl(m_sock_fd, F_SETFL, flags); + retvm_if(flags == -1, false, "Failed to fcntl(F_SETFL)[%d]", m_sock_fd); + + return true; +} + +bool socket::has_connected(void) +{ + int so_error; + socklen_t len = sizeof(so_error); + + if (getsockopt(m_sock_fd, SOL_SOCKET, SO_ERROR, &so_error, &len) == -1) { + _E("Failed to call getsockopt[%d]", m_sock_fd); + return false; + } + + if (so_error) { + _E("Failed to connect[%d]: %d", so_error); + return false; + } + + return true; +} + +bool socket::set_buffer_size(int type, int size) +{ + retv_if(m_sock_fd < 0, false); + + int ret = 0; + + ret = setsockopt(m_sock_fd, SOL_SOCKET, type, &size, sizeof(size)); + retvm_if(ret < 0, false, "Failed to call setsocketopt()"); + + return true; +} + +int socket::get_buffer_size(int type) +{ + retv_if(m_sock_fd < 0, false); + + int ret = 0; + int buf_size = 0; + socklen_t len; + + ret = getsockopt(m_sock_fd, SOL_SOCKET, type, &buf_size, &len); + retvm_if(ret < 0, -EPERM, "Failed to call getsocketopt()"); + + return buf_size; +} + +int socket::get_current_buffer_size(void) +{ + retv_if(m_sock_fd < 0, false); + + int queue_size = 0; + ioctl(m_sock_fd, TIOCOUTQ, &queue_size); + + return queue_size; +} + diff --git a/src/shared/socket.h b/src/shared/socket.h new file mode 100644 index 0000000..e9b6b66 --- /dev/null +++ b/src/shared/socket.h @@ -0,0 +1,83 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 __SOCKET_H__ +#define __SOCKET_H__ + +#include +#include +#include +#include +#include + +namespace ipc { + +class socket { +public: + socket(); + socket(int sock_fd); + socket(const socket &sock); + virtual ~socket(); + + virtual bool create(const std::string &path); + + bool connect(void); + bool bind(void); + bool listen(const int max_connections); + bool accept(socket &client_sock); + + bool close(void); + + int get_fd(void) const; + void set_fd(int sock_fd); + + int get_mode(void) const; + bool set_mode(int mode); + + bool set_blocking_mode(bool blocking); + bool set_recv_timeout(int timeout); + + /* type : SO_SNDBUF, SO_RCVBUF */ + bool set_buffer_size(int type, int size); + int get_buffer_size(int type); + int get_current_buffer_size(void); + + ssize_t send(const void *buffer, size_t size, bool select = false) const; + ssize_t recv(void* buffer, size_t size, bool select = false) const; + +protected: + bool create_by_type(const std::string &path, int type); + +private: + virtual ssize_t on_send(const void *buffer, size_t size) const = 0; + virtual ssize_t on_recv(void* buffer, size_t size) const = 0; + + int get_sock_type(void); + bool set_sock_type(int type); + bool has_connected(void); + + int m_sock_fd; + int m_mode; + std::atomic m_listening; + std::string m_path; +}; + +} + +#endif /* __SOCKET_H__ */ diff --git a/src/shared/stream_socket.cpp b/src/shared/stream_socket.cpp new file mode 100644 index 0000000..cdf8ccc --- /dev/null +++ b/src/shared/stream_socket.cpp @@ -0,0 +1,102 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 "stream_socket.h" + +#include +#include + +#include "sensor_log.h" + +using namespace ipc; + +stream_socket::stream_socket() +: socket() +{ +} + +stream_socket::~stream_socket() +{ +} + +bool stream_socket::create(const std::string &path) +{ + return socket::create_by_type(path, SOCK_STREAM); +} + +ssize_t stream_socket::on_send(const void *buffer, size_t size) const +{ + ssize_t len = 0; + size_t total_size = 0; + + do { + len = ::send(get_fd(), + reinterpret_cast(buffer) + total_size, + size - total_size, get_mode()); + + if (len < 0) { + if ((errno == EINTR) || (errno == EAGAIN) || (errno == EWOULDBLOCK)) { + usleep(1); + continue; + } + + _ERRNO(errno, _E, "Failed to send(%d, %#p, %x, %d) = %d", + get_fd(), buffer, total_size, size - total_size, len); + return -errno; + } + + total_size += len; + } while (total_size < size); + + return total_size; +} + +ssize_t stream_socket::on_recv(void *buffer, size_t size) const +{ + ssize_t len = 0; + size_t total_size = 0; + + do { + len = ::recv(get_fd(), + reinterpret_cast(buffer) + total_size, + size - total_size, + socket::get_mode()); + + if (len == 0) { + _E("Failed to recv(%d, %#p + %x, %d) = %d, because the peer performed shutdown", + get_fd(), buffer, total_size, size - total_size, len); + return -1; + } + + if (len < 0) { + if ((errno == EINTR) || (errno == EAGAIN) || (errno == EWOULDBLOCK)) { + usleep(10000); + continue; + } + + _ERRNO(errno, _E, "Failed to recv(%d, %#p, %x, %d) = %d", + get_fd(), buffer, total_size, size - total_size, len); + return -errno; + } + + total_size += len; + } while (total_size < size); + + return total_size; +} diff --git a/src/shared/stream_socket.h b/src/shared/stream_socket.h new file mode 100644 index 0000000..42af03e --- /dev/null +++ b/src/shared/stream_socket.h @@ -0,0 +1,41 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 __STREAM_SOCKET_H__ +#define __STREAM_SOCKET_H__ + +#include "socket.h" + +namespace ipc { + +class stream_socket : public socket { +public: + stream_socket(); + ~stream_socket(); + + bool create(const std::string &path); + +private: + ssize_t on_send(const void *buffer, size_t size) const; + ssize_t on_recv(void *buffer, size_t size) const; +}; + +} + +#endif /* __STREAM_SOCKET_H__ */ -- 2.7.4 From de8eba84f26115e69832945f0be6c8e55637f9e6 Mon Sep 17 00:00:00 2001 From: "kibak.yoon" Date: Tue, 4 Apr 2017 20:13:14 +0900 Subject: [PATCH 06/16] sensord: ipc: add event_loop class - event_loop class is a wrapper of g_main_loop. - event_loop class has the role of I/O multiplexing. - event_handler interface can be added to event_loop. - it would be better to make event_loop interface to use the other main_loop.. but now, it is not necessary yet. - todo-list - add/remove idle handler Change-Id: I74dd0636d43319e64fa2701f9b3c662e3f31c575 Signed-off-by: kibak.yoon --- src/shared/event_handler.h | 36 ++++++ src/shared/event_loop.cpp | 268 +++++++++++++++++++++++++++++++++++++++++++++ src/shared/event_loop.h | 102 +++++++++++++++++ 3 files changed, 406 insertions(+) create mode 100644 src/shared/event_handler.h create mode 100644 src/shared/event_loop.cpp create mode 100644 src/shared/event_loop.h diff --git a/src/shared/event_handler.h b/src/shared/event_handler.h new file mode 100644 index 0000000..26ab899 --- /dev/null +++ b/src/shared/event_handler.h @@ -0,0 +1,36 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 __EVENT_HANDLER_H__ +#define __EVENT_HANDLER_H__ + +namespace ipc { + +typedef unsigned int event_condition; + +class event_handler { +public: + virtual ~event_handler() {} + + virtual bool handle(int fd, event_condition condition) = 0; +}; + +} + +#endif /* __EVENT_HANDLER_H__ */ diff --git a/src/shared/event_loop.cpp b/src/shared/event_loop.cpp new file mode 100644 index 0000000..9bd596a --- /dev/null +++ b/src/shared/event_loop.cpp @@ -0,0 +1,268 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 "event_loop.h" + +#include +#include +#include +#include +#include +#include + +#include "sensor_log.h" +#include "event_handler.h" + +#define BAD_HANDLE 0 + +using namespace ipc; + +static gboolean g_io_handler(GIOChannel *ch, GIOCondition condition, gpointer data) +{ + uint64_t id; + int fd; + bool term; + unsigned int cond; + + cond = (unsigned int)condition; + + if (cond & (G_IO_HUP)) + cond &= ~(G_IO_IN & G_IO_OUT); + + handler_info *info = (handler_info *)data; + id = info->id; + fd = info->fd; + term = info->loop->is_terminator(fd); + + if (cond & G_IO_NVAL) + return FALSE; + + bool ret = info->handler->handle(fd, (event_condition)cond); + + if (!ret && !term) { + info->loop->remove_event(id); + return FALSE; + } + + return TRUE; +} + +static gint on_timer(gpointer data) +{ + event_loop *loop = (event_loop *)data; + loop->stop(); + + return FALSE; +} + +event_loop::event_loop() +: m_mainloop(NULL) +, m_running(false) +, m_terminating(false) +, m_sequence(1) +, m_term_fd(-1) +{ + m_mainloop = g_main_loop_new(NULL, FALSE); +} + +event_loop::event_loop(GMainLoop *mainloop) +: m_mainloop(NULL) +, m_running(true) +, m_terminating(false) +, m_sequence(1) +, m_term_fd(-1) +{ + if (m_mainloop) { + g_main_loop_quit(m_mainloop); + g_main_loop_unref(m_mainloop); + } + + m_mainloop = mainloop; +} + +event_loop::~event_loop() +{ + remove_all_events(); +} + +uint64_t event_loop::add_event(const int fd, const event_condition cond, event_handler *handler) +{ + GIOChannel *ch = NULL; + GSource *src = NULL; + + retvm_if(m_terminating.load(), BAD_HANDLE, + "Failed to add event, because event_loop is being terminated"); + + ch = g_io_channel_unix_new(fd); + retvm_if(!ch, BAD_HANDLE, "Failed to create g_io_channel_unix_new"); + + src = g_io_create_watch(ch, (GIOCondition)(cond)); + if (!src) { + g_io_channel_unref(ch); + _E("Failed to create g_io_create_watch"); + return BAD_HANDLE; + } + + uint64_t id = m_sequence++; + + handler_info *info = new(std::nothrow) handler_info(id, fd, ch, src, handler, this); + retvm_if(!info, BAD_HANDLE, "Failed to allocate memory"); + + g_source_set_callback(src, (GSourceFunc) g_io_handler, info, NULL); + g_source_attach(src, g_main_loop_get_context(m_mainloop)); + + m_infos[id] = info; + + /* _D("Added[%llu](fd:%d)", id, fd); */ + return id; +} + +uint64_t event_loop::add_idle_event(unsigned int priority, idle_handler *handler) +{ + GSource *src; + + retvm_if(m_terminating.load(), false, + "Failed to remove event, because event_loop is terminated"); + + src = g_idle_source_new(); + retvm_if(!src, false, "Failed to allocate memory"); + + g_source_unref(src); + + /* Not Supported yet */ + return false; +} + +bool event_loop::remove_event(uint64_t id, bool close_channel) +{ + auto it = m_infos.find(id); + retv_if(it == m_infos.end(), false); + + if (close_channel) + g_io_channel_shutdown(it->second->g_ch, TRUE, NULL); + + release_info(it->second); + m_infos.erase(it); + + /* _D("Removed[%llu]", id); */ + return true; +} + +void event_loop::remove_all_events(void) +{ + auto it = m_infos.begin(); + while (it != m_infos.end()) { + release_info(it->second); + it = m_infos.erase(it); + } +} + +void event_loop::release_info(handler_info *info) +{ + ret_if(!info->g_ch || info->id == 0); + + g_source_destroy(info->g_src); + g_source_unref(info->g_src); + + g_io_channel_unref(info->g_ch); + info->g_ch = NULL; + + delete info->handler; + info->handler = NULL; + + delete info; +} + +class terminator : public event_handler +{ +public: + terminator(event_loop *loop) + : m_loop(loop) + { } + + bool handle(int fd, event_condition condition) + { + m_loop->terminate(); + return false; + } + +private: + event_loop *m_loop; +}; + +bool event_loop::run(int timeout) +{ + retvm_if(!m_mainloop, false, "Invalid GMainLoop"); + retv_if(is_running(), false); + + if (timeout > 0) { + GSource *src = g_timeout_source_new(timeout); + g_source_set_callback(src, on_timer, this, NULL); + g_source_attach(src, g_main_loop_get_context(m_mainloop)); + g_source_unref(src); + } + + m_term_fd = eventfd(0, 0); + retv_if(m_term_fd == -1, false); + + terminator *handler = new(std::nothrow) terminator(this); + retvm_if(!handler, false, "Failed to allocate memory"); + + add_event(m_term_fd, EVENT_IN | EVENT_HUP | EVENT_NVAL, handler); + + m_running.store(true); + + _I("Started"); + g_main_loop_run(m_mainloop); +} + +void event_loop::stop(void) +{ + ret_if(!is_running() || m_terminating.load()); + + uint64_t term = 1; + m_terminating.store(true); + write(m_term_fd, &term, sizeof(uint64_t)); +} + +void event_loop::terminate(void) +{ + remove_all_events(); + + if (m_mainloop) { + g_main_loop_quit(m_mainloop); + g_main_loop_unref(m_mainloop); + m_mainloop = NULL; + } + + m_running.store(false); + m_terminating.store(false); + + _I("Terminated"); +} + +bool event_loop::is_running(void) +{ + return m_running.load(); +} + +bool event_loop::is_terminator(int fd) +{ + return (m_term_fd == fd); +} diff --git a/src/shared/event_loop.h b/src/shared/event_loop.h new file mode 100644 index 0000000..934a8b4 --- /dev/null +++ b/src/shared/event_loop.h @@ -0,0 +1,102 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 __EVENT_LOOP_H__ +#define __EVENT_LOOP_H__ + +#include +#include +#include +#include + +#include "event_handler.h" + +namespace ipc { + +enum event_condition_e { + EVENT_IN = G_IO_IN, + EVENT_OUT = G_IO_OUT, + EVENT_HUP = G_IO_HUP, + EVENT_NVAL = G_IO_NVAL, +}; + +/* move it to file */ +class idle_handler { + virtual ~idle_handler(); + bool handle(int fd); +}; + +class event_loop; + +class handler_info { +public: + handler_info(int64_t _id, int _fd, GIOChannel *_ch, GSource *_src, event_handler *_handler, event_loop *_loop) + : id(_id) + , fd(_fd) + , g_ch(_ch) + , g_src(_src) + , handler(_handler) + , loop(_loop) + {} + + uint64_t id; + int fd; + GIOChannel *g_ch; + GSource *g_src; + event_handler *handler; + event_loop *loop; +}; + +class event_loop { +public: + typedef unsigned int event_condition; + typedef bool (*idle_cb)(void *); + + event_loop(); + event_loop(GMainLoop *mainloop); + ~event_loop(); + + uint64_t add_event(const int fd, const event_condition cond, event_handler *handler); + uint64_t add_idle_event(unsigned int priority, idle_handler *handler); + + bool remove_event(uint64_t id, bool close_channel = false); + void remove_all_events(void); + + void release_info(handler_info *info); + + bool run(int timeout = 0); + void stop(void); + void terminate(void); + + bool is_running(void); + bool is_terminator(int fd); + +private: + GMainLoop *m_mainloop; + std::atomic m_running; + std::atomic m_terminating; + std::atomic m_sequence; + std::map m_infos; + + int m_term_fd; +}; + +} + +#endif /* __EVENT_LOOP_H__ */ -- 2.7.4 From ada7f2926f1be75807544324b6f63cb2606837e0 Mon Sep 17 00:00:00 2001 From: "kibak.yoon" Date: Tue, 4 Apr 2017 21:02:29 +0900 Subject: [PATCH 07/16] sensord: ipc: add message class - this class is a helper class for enconding/decoding the byte data. - message object includes the message header automatically. - this header provides message id/type/size/error. Change-Id: I03dc830baebf7a9bceac97013e9931f333f8f9d2 Signed-off-by: kibak.yoon --- src/shared/message.cpp | 159 +++++++++++++++++++++++++++++++++++++++++++++++++ src/shared/message.h | 74 +++++++++++++++++++++++ 2 files changed, 233 insertions(+) create mode 100644 src/shared/message.cpp create mode 100644 src/shared/message.h diff --git a/src/shared/message.cpp b/src/shared/message.cpp new file mode 100644 index 0000000..d7455eb --- /dev/null +++ b/src/shared/message.cpp @@ -0,0 +1,159 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 "message.h" + +#include +#include + +using namespace ipc; + +#define UNDEFINED_TYPE -2 + +static std::atomic sequence(0); + +message::message(size_t capacity) +: m_size(0) +, m_capacity(capacity) +, m_msg((char *)malloc(sizeof(char) * capacity)) +, ref_cnt(0) +{ + m_header.id = sequence++; + m_header.type = UNDEFINED_TYPE; + m_header.length = m_size; + m_header.err = 0; +} + +message::message(const void *msg, size_t sz) +: m_size(sz) +, m_capacity(sz) +, m_msg((char *)msg) +, ref_cnt(0) +{ + m_header.id = sequence++; + m_header.type = UNDEFINED_TYPE; + m_header.length = m_size; + m_header.err = 0; +} + +message::message(const message &msg) +: m_size(msg.m_size) +, m_capacity(msg.m_capacity) +, m_msg((char *)malloc(sizeof(char) * msg.m_capacity)) +, ref_cnt(0) +{ + ::memcpy(&m_header, &msg.m_header, sizeof(message_header)); + ::memcpy(m_msg, msg.m_msg, msg.m_size); +} + +message::message(int error) +: m_size(0) +, m_capacity(0) +, m_msg(NULL) +, ref_cnt(0) +{ + m_header.id = sequence++; + m_header.type = UNDEFINED_TYPE; + m_header.length = 0; + m_header.err = error; +} + +message::~message() +{ + if (m_msg && ref_cnt == 0) { + free(m_msg); + m_msg = NULL; + } +} + +void message::enclose(const void *msg, const size_t sz) +{ + if (!msg || sz == 0) + return; + + if (m_capacity < sz) + return; + + ::memcpy(reinterpret_cast(m_msg), msg, sz); + m_size = sz; + m_header.length = sz; +} + +void message::enclose(int error) +{ + m_header.err = error; + m_header.length = 0; + m_size = 0; +} + +void message::disclose(void *msg) +{ + if (!msg || !m_msg) + return; + + ::memcpy(msg, m_msg, m_size); +} + +uint32_t message::type(void) +{ + return m_header.type; +} + +void message::set_type(uint32_t msg_type) +{ + m_header.type = msg_type; +} + +size_t message::size(void) +{ + return m_size; +} + +/* TODO: remove ref/unref and use reference counting automatically */ +void message::ref(void) +{ + ref_cnt++; +} + +void message::unref(void) +{ + ref_cnt--; + + if (ref_cnt > 0 || !m_msg) + return; + + free(m_msg); + m_msg = NULL; + delete this; +} + +int message::ref_count(void) +{ + return ref_cnt; +} + +message_header *message::header(void) +{ + return &m_header; +} + +char *message::body(void) +{ + return m_msg; +} diff --git a/src/shared/message.h b/src/shared/message.h new file mode 100644 index 0000000..111cd9b --- /dev/null +++ b/src/shared/message.h @@ -0,0 +1,74 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 __MESSAGE_H__ +#define __MESSAGE_H__ + +#include /* size_t */ +#include + +#define MAX_MSG_CAPACITY 4096 +#define MAX_HEADER_RESERVED 3 + +namespace ipc { + +typedef struct message_header { + uint64_t id; + uint32_t type; + size_t length; + int32_t err; + void *ancillary[MAX_HEADER_RESERVED]; +} message_header; + +class message { +public: + message(size_t capacity = MAX_MSG_CAPACITY); + message(const void *msg, size_t size); + message(const message &msg); + message(int err); + ~message(); + + void enclose(const void *msg, const size_t size); + void enclose(int error); + void disclose(void *msg); + + uint32_t type(void); + void set_type(uint32_t type); + + size_t size(void); + + void ref(void); + void unref(void); + int ref_count(void); + + message_header *header(void); + char *body(void); + +private: + message_header m_header; + size_t m_size; + size_t m_capacity; + + char *m_msg; + std::atomic ref_cnt; +}; + +} + +#endif /* __MESSAGE_H__ */ -- 2.7.4 From eae39a262b2ec340fd928181fdb2f39e38072cf0 Mon Sep 17 00:00:00 2001 From: "kibak.yoon" Date: Tue, 4 Apr 2017 21:15:45 +0900 Subject: [PATCH 08/16] sensord: ipc: add channel class - channel class is a nexus to a socket which is capable of I/O operations, such as read, write, connect, and bind. - channel class provides: - the current state of the channel. - the configuration parameters of the channel. - the I/O operations that the channel supports. - channel class can support synchronous/asynchronous send/read call. - channel_handler: - is called by all I/O events(connect/disconnect/read and error) Change-Id: I85365e7cb443e969653353a83f8110ab690c4303 Signed-off-by: kibak.yoon --- src/shared/channel.cpp | 276 +++++++++++++++++++++++++++++++++++++++++++ src/shared/channel.h | 72 +++++++++++ src/shared/channel_handler.h | 41 +++++++ 3 files changed, 389 insertions(+) create mode 100644 src/shared/channel.cpp create mode 100644 src/shared/channel.h create mode 100644 src/shared/channel_handler.h diff --git a/src/shared/channel.cpp b/src/shared/channel.cpp new file mode 100644 index 0000000..b56d49e --- /dev/null +++ b/src/shared/channel.cpp @@ -0,0 +1,276 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 "channel.h" + +#include +#include +#include + +#include "sensor_log.h" + +using namespace ipc; + +class send_event_handler : public event_handler +{ +public: + send_event_handler(channel *ch, message *msg) + : m_ch(ch) + , m_msg(msg) + { } + + bool handle(int fd, event_condition condition) + { + if (!m_ch || !m_ch->is_connected()) + return false; + + if (condition & (EVENT_IN | EVENT_HUP)) + return false; + + if (!m_ch->send_sync(m_msg)) + return false; + + if (m_msg) + m_msg->unref(); + + return false; + } + +private: + channel *m_ch; + message *m_msg; +}; + +class read_event_handler : public event_handler +{ +public: + read_event_handler(channel *ch) + : m_ch(ch) + { } + + bool handle(int fd, event_condition condition) + { + message msg; + + if (!m_ch || !m_ch->is_connected()) + return false; + + if (condition & (EVENT_OUT | EVENT_HUP)) + return false; + + if (!m_ch->read_sync(msg)) + return false; + + return false; + } + +private: + channel *m_ch; +}; + +channel::channel(socket *sock) +: m_fd(sock->get_fd()) +, m_event_id(0) +, m_socket(sock) +, m_handler(NULL) +, m_loop(NULL) +, m_connected(false) +{ +} + +channel::~channel() +{ + /* disconnect() should not be called here */ +} + +void channel::bind(channel_handler *handler, event_loop *loop) +{ + m_handler = handler; + m_loop = loop; + m_connected.store(true); + + if (m_handler) + m_handler->connected(this); +} + +bool channel::connect(channel_handler *handler, event_loop *loop) +{ + if (!m_socket->connect()) + return false; + + bind(handler, loop); + return true; +} + +void channel::disconnect(void) +{ + ret_if(!is_connected()); + m_connected.store(false); + + if (m_handler) { + m_handler->disconnected(this); + m_handler = NULL; + } + + if (m_loop) { + m_loop->remove_event(m_event_id, true); + m_loop = NULL; + m_event_id = 0; + } + + if (m_socket) { + delete m_socket; + m_socket = NULL; + } +} + +bool channel::send(message *msg) +{ + retv_if(!m_loop, false); + + /* TODO: check buffer size(is there any linux api for this?) */ + int cur_buffer_size = m_socket->get_current_buffer_size(); + retvm_if(!cur_buffer_size > 40000, false, "Failed to send data"); + + send_event_handler *handler = new(std::nothrow) send_event_handler(this, msg); + retvm_if(!handler, false, "Failed to allocate memory"); + + msg->ref(); + + m_loop->add_event(m_socket->get_fd(), + (EVENT_OUT | EVENT_HUP | EVENT_NVAL) , handler); + + return true; +} + +bool channel::send_sync(message *msg) +{ + retv_if(!msg, false); + + ssize_t size = 0; + char *buf = msg->body(); + + /* header */ + size = m_socket->send(reinterpret_cast(msg->header()), + sizeof(message_header), true); + retv_if(size <= 0, false); + retv_if(msg->size() <= 0, true); + + /* body */ + size = m_socket->send(buf, msg->size(), true); + retv_if(size <= 0, false); + + return true; +} + +bool channel::read(void) +{ + retv_if(!m_loop, false); + + read_event_handler *handler = new(std::nothrow) read_event_handler(this); + retvm_if(!handler, false, "Failed to allocate memory"); + + m_loop->add_event(m_socket->get_fd(), (EVENT_IN | EVENT_HUP | EVENT_NVAL), handler); + + return true; +} + +bool channel::read_sync(message &msg) +{ + message_header header; + ssize_t size = 0; + char buf[MAX_MSG_CAPACITY]; + + /* header */ + size = m_socket->recv(&header, sizeof(message_header), true); + retv_if(size <= 0, false); + + /* check error from header */ + if (m_handler && header.err != 0) { + m_handler->error_caught(this, header.err); + msg.header()->err = header.err; + return true; + } + + /* body */ + if (header.length > 0) { + size = m_socket->recv(&buf, header.length, true); + retv_if(size <= 0, false); + } + + buf[header.length] = '\0'; + msg.enclose(reinterpret_cast(buf), header.length); + msg.set_type(header.type); + msg.header()->err = header.err; + + if (m_handler) + m_handler->read(this, msg); + + return true; +} + +bool channel::is_connected(void) +{ + return m_connected.load(); +} + +bool channel::set_option(int type, int value) +{ + switch (type) { + case SO_SNDBUF: + m_socket->set_buffer_size(type, value); + break; + case SO_RCVBUF: + m_socket->set_buffer_size(type, value); + break; + default: + break; + } + + return true; +} + +bool channel::get_option(int type, int &value) const +{ + switch (type) { + case 0: + value = m_socket->get_current_buffer_size(); + break; + case SO_SNDBUF: + value = m_socket->get_buffer_size(type); + break; + case SO_RCVBUF: + value = m_socket->get_buffer_size(type); + break; + default: + break; + } + + return true; +} + +int channel::get_fd(void) const +{ + return m_fd; +} + +void channel::set_event_id(uint64_t id) +{ + m_event_id = id; +} diff --git a/src/shared/channel.h b/src/shared/channel.h new file mode 100644 index 0000000..e37a7a9 --- /dev/null +++ b/src/shared/channel.h @@ -0,0 +1,72 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 __CHANNEL_H__ +#define __CHANNEL_H__ + +#include +#include + +#include "socket.h" +#include "message.h" +#include "event_loop.h" +#include "channel_handler.h" + +namespace ipc { + +class channel_handler; + +class channel { +public: + /* move owernership of the socket to the channel */ + channel(socket *sock); + ~channel(); + + void bind(channel_handler *handler, event_loop *loop); + + bool connect(channel_handler *handler, event_loop *loop); + void disconnect(void); + + bool is_connected(void); + + bool send(message *msg); + bool send_sync(message *msg); + + bool read(void); + bool read_sync(message &msg); + + bool get_option(int type, int &value) const; + bool set_option(int type, int value); + + int get_fd(void) const; + void set_event_id(uint64_t id); + +private: + int m_fd; + uint64_t m_event_id; + socket *m_socket; + channel_handler *m_handler; + event_loop *m_loop; + + std::atomic m_connected; +}; + +} + +#endif /* __CHANNEL_H__ */ diff --git a/src/shared/channel_handler.h b/src/shared/channel_handler.h new file mode 100644 index 0000000..b420fbd --- /dev/null +++ b/src/shared/channel_handler.h @@ -0,0 +1,41 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 __CHANNEL_HANDLER_H__ +#define __CHANNEL_HANDLER_H__ + +namespace ipc { + +class channel; +class message; + +class channel_handler { +public: + virtual ~channel_handler() {} + + virtual void connected(channel *ch) = 0; + virtual void disconnected(channel *ch) = 0; + virtual void read(channel *ch, message &msg) = 0; + virtual void read_complete(channel *ch) = 0; + virtual void error_caught(channel *ch, int error) = 0; +}; + +} + +#endif /* __CHANNEL_HANDLER_H__ */ -- 2.7.4 From 141a78d2459788d2f51f4a99c5acd9a11258e2c7 Mon Sep 17 00:00:00 2001 From: "kibak.yoon" Date: Tue, 4 Apr 2017 21:30:31 +0900 Subject: [PATCH 09/16] sensord: ipc: add ipc_client class - ipc_client class is a helper for client. - ipc_client class that makes it easy to connect a channel to use for clients. - it creates and connects socket/channel/channel event_handler. Change-Id: If75a4ab542d3623a785ccf8bccbd66628b9646db Signed-off-by: kibak.yoon --- src/shared/channel_event_handler.cpp | 92 ++++++++++++++++++++++++++++++++++++ src/shared/channel_event_handler.h | 52 ++++++++++++++++++++ src/shared/ipc_client.cpp | 92 ++++++++++++++++++++++++++++++++++++ src/shared/ipc_client.h | 49 +++++++++++++++++++ 4 files changed, 285 insertions(+) create mode 100644 src/shared/channel_event_handler.cpp create mode 100644 src/shared/channel_event_handler.h create mode 100644 src/shared/ipc_client.cpp create mode 100644 src/shared/ipc_client.h diff --git a/src/shared/channel_event_handler.cpp b/src/shared/channel_event_handler.cpp new file mode 100644 index 0000000..9045a88 --- /dev/null +++ b/src/shared/channel_event_handler.cpp @@ -0,0 +1,92 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 "channel_event_handler.h" + +#include "channel.h" +#include "channel_handler.h" +#include "sensor_log.h" + +using namespace ipc; + +channel_event_handler::channel_event_handler(channel *ch, channel_handler *handler) +: m_ch(ch) +, m_handler(handler) +{ +} + +channel_event_handler::~channel_event_handler() +{ + m_ch = NULL; + m_handler = NULL; +} + +bool channel_event_handler::handle(int fd, event_condition condition) +{ + message msg; + + if (!m_ch || !m_ch->is_connected()) + return false; + + if (condition & (EVENT_HUP)) { + m_ch->disconnect(); + delete m_ch; + m_ch = NULL; + return false; + } + + if (!m_ch->read_sync(msg)) { + m_ch->disconnect(); + delete m_ch; + m_ch = NULL; + return false; + } + + return true; +} + +void channel_event_handler::connected(channel *ch) +{ + if (m_handler) + m_handler->connected(ch); +} + +void channel_event_handler::disconnected(channel *ch) +{ + if (m_handler) + m_handler->disconnected(ch); +} + +void channel_event_handler::read(channel *ch, message &msg) +{ + if (m_handler) + m_handler->read(ch, msg); +} + +void channel_event_handler::read_complete(channel *ch) +{ + if (m_handler) + m_handler->read_complete(ch); +} + +void channel_event_handler::error_caught(channel *ch, int error) +{ + if (m_handler) + m_handler->error_caught(ch, error); +} diff --git a/src/shared/channel_event_handler.h b/src/shared/channel_event_handler.h new file mode 100644 index 0000000..252c7ee --- /dev/null +++ b/src/shared/channel_event_handler.h @@ -0,0 +1,52 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 __CHANNEL_EVENT_HANDLER_H__ +#define __CHANNEL_EVENT_HANDLER_H__ + +#include + +#include "event_handler.h" +#include "channel_handler.h" + +namespace ipc { + +class channel; + +class channel_event_handler : public event_handler, public channel_handler { +public: + channel_event_handler(channel *ch, channel_handler *handler); + virtual ~channel_event_handler(); + + bool handle(int fd, event_condition condition); + + void connected(channel *ch); + void disconnected(channel *ch); + void read(channel *ch, message &msg); + void read_complete(channel *ch); + void error_caught(channel *ch, int error); + +private: + channel *m_ch; + channel_handler *m_handler; +}; + +} + +#endif /* __CHANNEL_EVENT_HANDLER_H__ */ diff --git a/src/shared/ipc_client.cpp b/src/shared/ipc_client.cpp new file mode 100644 index 0000000..71fdde4 --- /dev/null +++ b/src/shared/ipc_client.cpp @@ -0,0 +1,92 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 "ipc_client.h" + +#include "sensor_log.h" +#include "stream_socket.h" +#include "event_handler.h" +#include "channel_event_handler.h" + +using namespace ipc; + +ipc_client::ipc_client(const std::string &path) +{ + m_path = path; +} + +ipc_client::~ipc_client() +{ +} + +bool ipc_client::set_option(int option, int value) +{ + return true; +} + +bool ipc_client::set_option(const std::string &option, int value) +{ + return true; +} + +channel *ipc_client::connect(channel_handler *handler) +{ + return connect(handler, NULL); +} + +channel *ipc_client::connect(channel_handler *handler, event_loop *loop) +{ + socket *sock; + channel *ch; + channel_event_handler *ev_handler; + + sock = new(std::nothrow) stream_socket(); + retvm_if(!sock, NULL, "Failed to allocate memory"); + + if (!sock->create(m_path)) { + delete sock; + return NULL; + } + + ch = new(std::nothrow) channel(sock); + if (!ch) { + delete sock; + _E("Failed to allocate memory"); + return NULL; + } + + ev_handler = new(std::nothrow) channel_event_handler(ch, handler); + if (!ev_handler) { + delete ch; + delete sock; + _E("Faield to allocate memory"); + return NULL; + } + + ch->connect(ev_handler, loop); + + if (loop) { + uint64_t id = loop->add_event(sock->get_fd(), + (EVENT_IN | EVENT_HUP | EVENT_NVAL), ev_handler); + ch->set_event_id(id); + } + + _I("Connected"); + return ch; +} diff --git a/src/shared/ipc_client.h b/src/shared/ipc_client.h new file mode 100644 index 0000000..8f52678 --- /dev/null +++ b/src/shared/ipc_client.h @@ -0,0 +1,49 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 __IPC_CLIENT_H__ +#define __IPC_CLIENT_H__ + +#include + +#include "channel.h" +#include "channel_handler.h" +#include "event_loop.h" + +namespace ipc { + +class ipc_client { +public: + ipc_client(const std::string &path); + ~ipc_client(); + + bool set_option(int option, int value); + bool set_option(const std::string &option, int value); + + /* call channel->disconnect() after you have used it */ + channel *connect(channel_handler *handler); + channel *connect(channel_handler *handler, event_loop *loop); + +private: + std::string m_path; +}; + +} + +#endif /* __IPC_CLIENT_H__ */ -- 2.7.4 From 94b08af3a6ff275818e9e6104dc556d93d95e36a Mon Sep 17 00:00:00 2001 From: "kibak.yoon" Date: Wed, 5 Apr 2017 09:57:43 +0900 Subject: [PATCH 10/16] sensord: ipc: add ipc_server class - ipc_server class is a helper for server - ipc_server class that makes it easy to bind/listen/accept a channel to use for server. - it creates and bind/accepts socket/channel/channel_event_handler Change-Id: If79e27a6babcf73126b56f65e750176a9ddd5c78 Signed-off-by: kibak.yoon --- src/shared/accept_event_handler.cpp | 47 +++++++++++++++ src/shared/accept_event_handler.h | 42 ++++++++++++++ src/shared/ipc_server.cpp | 111 ++++++++++++++++++++++++++++++++++++ src/shared/ipc_server.h | 59 +++++++++++++++++++ 4 files changed, 259 insertions(+) create mode 100644 src/shared/accept_event_handler.cpp create mode 100644 src/shared/accept_event_handler.h create mode 100644 src/shared/ipc_server.cpp create mode 100644 src/shared/ipc_server.h diff --git a/src/shared/accept_event_handler.cpp b/src/shared/accept_event_handler.cpp new file mode 100644 index 0000000..527d967 --- /dev/null +++ b/src/shared/accept_event_handler.cpp @@ -0,0 +1,47 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 "accept_event_handler.h" + +#include "sensor_log.h" +#include "ipc_server.h" + +using namespace ipc; + +accept_event_handler::accept_event_handler(ipc_server *server) +: m_server(server) +{ +} + +bool accept_event_handler::handle(int fd, event_condition condition) +{ + retv_if((condition & (EVENT_HUP)), false); + + stream_socket *cli_sock = new(std::nothrow) stream_socket(); + retvm_if(!cli_sock, false, "Failed to allocate memory"); + + m_server->accept(*cli_sock); + + channel *_ch = new(std::nothrow) channel(cli_sock); + retvm_if(!_ch, false, "Failed to allocate memory"); + + m_server->register_channel(cli_sock->get_fd(), _ch); + + return true; +} diff --git a/src/shared/accept_event_handler.h b/src/shared/accept_event_handler.h new file mode 100644 index 0000000..814f560 --- /dev/null +++ b/src/shared/accept_event_handler.h @@ -0,0 +1,42 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 __ACCEPT_EVENT_HANDLER__ +#define __ACCEPT_EVENT_HANDLER__ + +#include "event_handler.h" + +namespace ipc { + +class ipc_server; + +class accept_event_handler : public event_handler +{ +public: + accept_event_handler(ipc_server *server); + + bool handle(int fd, event_condition condition); + +private: + ipc_server *m_server; +}; + +} + +#endif /* __ACCEPT_EVENT_HANDLER__ */ diff --git a/src/shared/ipc_server.cpp b/src/shared/ipc_server.cpp new file mode 100644 index 0000000..9723a98 --- /dev/null +++ b/src/shared/ipc_server.cpp @@ -0,0 +1,111 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 "ipc_server.h" + +#include "channel.h" +#include "sensor_log.h" +#include "event_loop.h" +#include "channel_event_handler.h" +#include "accept_event_handler.h" + +using namespace ipc; + +#define MAX_CONNECTIONS 1000 + +ipc_server::ipc_server(const std::string &path) +{ + m_accept_sock.create(path); +} + +ipc_server::~ipc_server() +{ +} + +bool ipc_server::set_option(int option, int value) +{ + /* TODO */ + return true; +} + +bool ipc_server::set_option(const std::string &option, int value) +{ + /* TODO */ + return true; +} + +void ipc_server::accept(ipc::socket &cli_sock) +{ + m_accept_sock.accept(cli_sock); + + _I("Accepted[%d]", cli_sock.get_fd()); +} + +bool ipc_server::bind(channel_handler *handler, event_loop *loop) +{ + m_handler = handler; + m_event_loop = loop; + + m_accept_sock.bind(); + m_accept_sock.listen(MAX_CONNECTIONS); + + register_acceptor(); + + _I("Bound[%d]", m_accept_sock.get_fd()); + return true; +} + +void ipc_server::register_channel(int fd, channel *ch) +{ + channel_event_handler *ev_handler = new(std::nothrow) channel_event_handler(ch, m_handler); + retm_if(!ev_handler, "Failed to allocate memory"); + + ch->bind(ev_handler, m_event_loop); + uint64_t id = m_event_loop->add_event(fd, + (event_condition)(EVENT_IN | EVENT_HUP | EVENT_NVAL), ev_handler); + + if (id == 0) + delete ev_handler; +} + +void ipc_server::register_acceptor(void) +{ + int fd = m_accept_sock.get_fd(); + + m_accept_handler = new(std::nothrow) accept_event_handler(this); + retm_if(!m_accept_handler, "Failed to allocate memory"); + + uint64_t id = m_event_loop->add_event(fd, + (event_condition)(EVENT_IN | EVENT_HUP | EVENT_NVAL), m_accept_handler); + + if (id == 0) { + delete m_accept_handler; + m_accept_handler = NULL; + } +} + +bool ipc_server::close(void) +{ + m_accept_sock.close(); + + m_handler = NULL; + + _I("Closed"); + return true; +} diff --git a/src/shared/ipc_server.h b/src/shared/ipc_server.h new file mode 100644 index 0000000..7e033d0 --- /dev/null +++ b/src/shared/ipc_server.h @@ -0,0 +1,59 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 __IPC_SERVER_H__ +#define __IPC_SERVER_H__ + +#include + +#include "stream_socket.h" +#include "channel.h" +#include "channel_handler.h" +#include "accept_event_handler.h" +#include "event_loop.h" + +namespace ipc { + +class ipc_server { +public: + ipc_server(const std::string &path); + ~ipc_server(); + + bool set_option(int option, int value); + bool set_option(const std::string &option, int value); + + bool bind(channel_handler *handler, event_loop *loop); + bool close(void); + + /* TODO: only accept_handler should use these functions */ + void accept(ipc::socket &cli_sock); + void register_channel(int fd, channel *ch); + void register_acceptor(void); + +private: + stream_socket m_accept_sock; + + event_loop *m_event_loop; + channel_handler *m_handler; + accept_event_handler *m_accept_handler; +}; + +} + +#endif /* __IPC_SERVER_H__ */ -- 2.7.4 From 4552f30d4227b2a14477b19246b1faacd0036ba2 Mon Sep 17 00:00:00 2001 From: "kibak.yoon" Date: Wed, 5 Apr 2017 10:19:13 +0900 Subject: [PATCH 11/16] sensord: remove build warnings in ipc-utils - warning: control reaches end of non-void function [-Wreturn-type] - warning: ignoring return value [-Wunused-result] Change-Id: Id172b9e32bfe45543b16dc9a0726bc1cc0c11441 Signed-off-by: kibak.yoon --- src/shared/event_loop.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/shared/event_loop.cpp b/src/shared/event_loop.cpp index 9bd596a..73854b5 100644 --- a/src/shared/event_loop.cpp +++ b/src/shared/event_loop.cpp @@ -230,6 +230,8 @@ bool event_loop::run(int timeout) _I("Started"); g_main_loop_run(m_mainloop); + + return true; } void event_loop::stop(void) @@ -237,8 +239,11 @@ void event_loop::stop(void) ret_if(!is_running() || m_terminating.load()); uint64_t term = 1; + ssize_t size; m_terminating.store(true); - write(m_term_fd, &term, sizeof(uint64_t)); + size = write(m_term_fd, &term, sizeof(uint64_t)); + + retm_if(size != sizeof(ssize_t), "Failed to write[%d]", m_term_fd); } void event_loop::terminate(void) -- 2.7.4 From 1626d4fcda3c62ab1c76edef565660cbb3730be4 Mon Sep 17 00:00:00 2001 From: "kibak.yoon" Date: Wed, 5 Apr 2017 10:29:52 +0900 Subject: [PATCH 12/16] sensord: ipc: add unit testcases - test a connection between ipc_client and ipc_server - test 2 clients - test 100 clients - test 1 client with 2 channels - test 30 clients with large message - test 3 normal client and 1 client with small recv buffer - test 3 normal client and 1 client witch sleeps 10 seconds Change-Id: I33b2e782872b51d42fc4a68b84bd5d6fe758964f Signed-off-by: kibak.yoon --- src/sensorctl/testcase/unit_ipc.cpp | 524 ++++++++++++++++++++++++++++++++++++ 1 file changed, 524 insertions(+) create mode 100644 src/sensorctl/testcase/unit_ipc.cpp diff --git a/src/sensorctl/testcase/unit_ipc.cpp b/src/sensorctl/testcase/unit_ipc.cpp new file mode 100644 index 0000000..4528562 --- /dev/null +++ b/src/sensorctl/testcase/unit_ipc.cpp @@ -0,0 +1,524 @@ +/* + * sensorctl + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 +#include +#include + +#include "shared/channel.h" +#include "shared/channel_handler.h" +#include "shared/ipc_client.h" +#include "shared/ipc_server.h" + +#include "log.h" +#include "test_bench.h" + +using namespace ipc; + +#define MAX_BUF_SIZE 4096 +#define TEST_PATH "/run/.sensord_test.socket" + +typedef bool (*process_func_t)(const char *msg, int size, int count); + +static pid_t run_process(process_func_t func, const char *msg, int size, int count) +{ + pid_t pid = fork(); + if (pid < 0) + return -1; + + if (pid == 0) { + if (!func(msg, size, count)) + _E("Failed to run process\n"); + exit(0); + } + + return pid; +} + +class test_echo_server_handler : public channel_handler +{ +public: + void connected(channel *ch) {} + void disconnected(channel *ch) {} + void read(channel *ch, message &msg) + { + char buf[MAX_BUF_SIZE]; + + message *reply = new(std::nothrow) message(); + RETM_IF(!reply, "Failed to allocate memory"); + + msg.disclose(buf); + reply->enclose(buf, MAX_BUF_SIZE); + + ch->send(reply); + } + void read_complete(channel *ch) {} + void error_caught(channel *ch, int error) {} +}; + +/* IPC Echo Server */ +static bool run_ipc_server_echo(const char *str, int size, int count) +{ + event_loop eloop; + + ipc_server server(TEST_PATH); + test_echo_server_handler handler; + + server.set_option("max_connection", 10); + server.set_option(SO_TYPE, SOCK_STREAM); + server.bind(&handler, &eloop); + + eloop.run(18000); + server.close(); + + return true; +} + +class test_client_handler_30_1M : public channel_handler +{ +public: + void connected(channel *ch) {} + void disconnected(channel *ch) {} + void read(channel *ch, message &msg) {} + void read_complete(channel *ch) {} + void error_caught(channel *ch, int error) {} +}; + +/* IPC Client Sleep Test(4096Kb * 1024) */ +static bool run_ipc_client_sleep_10s(const char *str, int size, int count) +{ + ipc_client client(TEST_PATH); + test_client_handler_30_1M client_handler; + + channel *ch = client.connect(&client_handler, NULL); + ASSERT_NE(ch, 0); + + message msg; + message reply; + char buf[MAX_BUF_SIZE] = {'1', '1', '1',}; + + msg.enclose(buf, MAX_BUF_SIZE); + + usleep(10000); + ch->send_sync(&msg); + + /* Test */ + sleep(1); + + ch->read_sync(reply); + reply.disclose(buf); + + int ret = strncmp(buf, "111", 3); + ASSERT_EQ(ret, 0); + ASSERT_EQ(reply.size(), MAX_BUF_SIZE); + + ch->disconnect(); + delete ch; + + return true; +} + +/* IPC Client With Small Buffer Test(4096Kb * 1024) */ +static bool run_ipc_client_small_buffer(const char *str, int size, int count) +{ + ipc_client client(TEST_PATH); + test_client_handler_30_1M client_handler; + + channel *ch = client.connect(&client_handler, NULL); + ASSERT_NE(ch, 0); + + int ret; + message msg; + message reply; + char buf[MAX_BUF_SIZE] = {'1', '1', '1',}; + + msg.enclose(buf, MAX_BUF_SIZE); + + usleep(10000); + + int buf_size; + ch->get_option(SO_RCVBUF, buf_size); + _I("Before: Buffer size : %d\n", buf_size); + + ch->set_option(SO_RCVBUF, buf_size/2048); + ch->get_option(SO_RCVBUF, buf_size); + _I("After: Buffer size : %d\n", buf_size); + + for (int i = 0; i < 1024; ++i) { + ch->send_sync(&msg); + ch->read_sync(reply); + } + + reply.disclose(buf); + + ret = strncmp(buf, "111", 3); + ASSERT_EQ(ret, 0); + ASSERT_EQ(reply.size(), MAX_BUF_SIZE); + + ch->disconnect(); + delete ch; + + return true; +} + +/* IPC Client Test(4K * 256) */ +static bool run_ipc_client_1M(const char *str, int size, int count) +{ + ipc_client client(TEST_PATH); + test_client_handler_30_1M client_handler; + + channel *ch = client.connect(&client_handler, NULL); + ASSERT_NE(ch, 0); + + int ret; + message msg; + message reply; + char buf[MAX_BUF_SIZE] = {'1', '1', '1',}; + + msg.enclose(buf, MAX_BUF_SIZE); + + usleep(10000); + + for (int i = 0; i < 256; ++i) { + ch->send_sync(&msg); + ch->read_sync(reply); + } + + reply.disclose(buf); + + ret = strncmp(buf, "111", 3); + ASSERT_EQ(ret, 0); + ASSERT_EQ(reply.size(), MAX_BUF_SIZE); + + ch->disconnect(); + delete ch; + + return true; +} + +/* IPC Server Test(Not Echo) */ +class test_server_handler : public channel_handler +{ +public: + void connected(channel *ch) {} + void disconnected(channel *ch) {} + void read(channel *ch, message &msg) + { + char buf[MAX_BUF_SIZE]; + msg.disclose(buf); + + message *reply = new(std::nothrow) message(); + if (!reply) return; + + reply->enclose("TEXTTEXTTEXTTEXT", 16); + ch->send(reply); + } + void read_complete(channel *ch) {} + void error_caught(channel *ch, int error) {} +}; + +static bool run_ipc_server(const char *str, int size, int count) +{ + event_loop eloop; + + ipc_server server(TEST_PATH); + test_server_handler handler; + + server.set_option("max_connection", 10); + server.set_option(SO_TYPE, SOCK_STREAM); + server.bind(&handler, &eloop); + + /* run main loop for 5 seconds */ + eloop.run(5000); + + server.close(); + + return true; +} + +/* IPC Client Test(Not Echo) */ +class test_client_handler : public channel_handler +{ +public: + void connected(channel *ch) {} + void disconnected(channel *ch) {} + void read(channel *ch, message &msg) {} + void read_complete(channel *ch) {} + void error_caught(channel *ch, int error) {} +}; + +static bool run_ipc_client_2_channel_message(const char *str, int size, int count) +{ + ipc_client client(TEST_PATH); + test_client_handler client_handler; + channel *ch[2]; + int ret; + message msg; + message reply; + char buf[MAX_BUF_SIZE]; + + ch[0] = client.connect(&client_handler, NULL); + ASSERT_NE(ch[0], 0); + + msg.enclose("TESTTESTTEST", 12); + ch[0]->send_sync(&msg); + usleep(100000); + ch[0]->read_sync(reply); + reply.disclose(buf); + ret = strncmp(buf, "TEXTTEXTTEXTTEXT", 16); + ASSERT_EQ(ret, 0); + + ch[1] = client.connect(&client_handler, NULL); + ASSERT_NE(ch[1], 0); + + msg.enclose("TESTTESTTEST", 12); + ch[1]->send_sync(&msg); + usleep(100000); + ch[1]->read_sync(reply); + reply.disclose(buf); + ret = strncmp(buf, "TEXTTEXTTEXTTEXT", 16); + ASSERT_EQ(ret, 0); + + ch[0]->disconnect(); + ch[1]->disconnect(); + delete ch[0]; + delete ch[1]; + + return true; +} + +static bool run_ipc_client_2_channel(const char *str, int size, int count) +{ + ipc_client client(TEST_PATH); + test_client_handler client_handler; + channel *ch[2]; + + ch[0] = client.connect(&client_handler, NULL); + ASSERT_NE(ch[0], 0); + ch[1] = client.connect(&client_handler, NULL); + ASSERT_NE(ch[1], 0); + ASSERT_NE(ch[1], ch[0]); + + ch[0]->disconnect(); + ch[1]->disconnect(); + delete ch[0]; + delete ch[1]; + + return true; +} + +static bool run_ipc_client(const char *str, int size, int count) +{ + ipc_client client(TEST_PATH); + test_client_handler client_handler; + + channel *ch = client.connect(&client_handler, NULL); + ASSERT_NE(ch, 0); + + int ret; + message msg; + message reply; + char buf[MAX_BUF_SIZE]; + + msg.enclose("TESTTESTTEST", 12); + ch->send_sync(&msg); + + usleep(100000); + + ch->read_sync(reply); + reply.disclose(buf); + + ret = strncmp(buf, "TEXTTEXTTEXTTEXT", 16); + ASSERT_EQ(ret, 0); + + ch->disconnect(); + delete ch; + + return true; +} + +/** + * @brief Test 3 client + 1 client which sleeps 10 seconds + */ +TESTCASE(sensor_ipc_client_sleep_1s, sleep_1s_p) +{ + pid_t pid = run_process(run_ipc_server_echo, NULL, 0, 0); + EXPECT_GE(pid, 0); + + usleep(100000); + + for (int i = 0; i < 3; ++i) { + pid = run_process(run_ipc_client_1M, NULL, 0, 0); + EXPECT_GE(pid, 0); + } + + bool ret = run_ipc_client_sleep_10s(NULL, 0, 0); + ASSERT_TRUE(ret); + + usleep(100000); + + return true; +} + +/** + * @brief Test 3 client + 1 client which has small recv buffer + */ +TESTCASE(sensor_ipc_client_small_2240, ipc_client_small_2240_p) +{ + pid_t pid = run_process(run_ipc_server_echo, NULL, 0, 0); + EXPECT_GE(pid, 0); + + usleep(100000); + + for (int i = 0; i < 3; ++i) { + pid = run_process(run_ipc_client_1M, NULL, 0, 0); + EXPECT_GE(pid, 0); + } + + bool ret = run_ipc_client_small_buffer(NULL, 0, 0); + ASSERT_TRUE(ret); + + usleep(100000); + + return true; +} + +/** + * @brief Test 30 ipc_client with 1M message + */ +TESTCASE(sensor_ipc_30_client_1M, ipc_client_p_30_1M) +{ + pid_t pid = run_process(run_ipc_server_echo, NULL, 0, 0); + EXPECT_GE(pid, 0); + + usleep(100000); + + for (int i = 0; i < 30; ++i) { + pid = run_process(run_ipc_client_1M, NULL, 0, 0); + EXPECT_GE(pid, 0); + } + + bool ret = run_ipc_client_1M(NULL, 0, 0); + ASSERT_TRUE(ret); + + usleep(100000); + + return true; +} + +/** + * @brief Test 2 channel of 1 client with message + */ +TESTCASE(sensor_ipc_client_2_channel_message, 2_channel_message_p) +{ + pid_t pid = run_process(run_ipc_server, NULL, 0, 0); + EXPECT_GE(pid, 0); + + usleep(100000); + + bool ret = run_ipc_client_2_channel_message(NULL, 0, 0); + ASSERT_TRUE(ret); + + usleep(100000); + + return true; +} + +/** + * @brief Test 2 channel of 1 client + */ +TESTCASE(sensor_ipc_client_2_channel, 2_channel_p) +{ + pid_t pid = run_process(run_ipc_server, NULL, 0, 0); + EXPECT_GE(pid, 0); + + usleep(100000); + + bool ret = run_ipc_client_2_channel(NULL, 0, 0); + ASSERT_TRUE(ret); + + usleep(100000); + + return true; +} + +/** + * @brief Test 100 ipc_client + */ +TESTCASE(sensor_ipc_100_client, ipc_client_p_100) +{ + pid_t pid = run_process(run_ipc_server, NULL, 0, 0); + EXPECT_GE(pid, 0); + + usleep(100000); + + for (int i = 0; i < 99; ++i) { + pid = run_process(run_ipc_client, NULL, 0, 0); + EXPECT_GE(pid, 0); + } + + bool ret = run_ipc_client(NULL, 0, 0); + ASSERT_TRUE(ret); + + usleep(100000); + + return true; +} + +/** + * @brief Test 2 ipc_client + */ +TESTCASE(sensor_ipc_2_client, ipc_client_p_2) +{ + pid_t pid = run_process(run_ipc_server, NULL, 0, 0); + EXPECT_GE(pid, 0); + + usleep(100000); + + pid = run_process(run_ipc_client, NULL, 0, 0); + EXPECT_GE(pid, 0); + + bool ret = run_ipc_client(NULL, 0, 0); + ASSERT_TRUE(ret); + + usleep(100000); + + return true; +} + +/** + * @brief Test ipc_client/ipc_server class + * @details 1. connect/disconnect + * 2. send "TEST" message from client to server + * 3. check that message in server handler + */ +TESTCASE(sensor_ipc_client_0, ipc_client_p_0) +{ + pid_t pid = run_process(run_ipc_server, NULL, 0, 0); + EXPECT_GE(pid, 0); + + usleep(100000); + + bool ret = run_ipc_client(NULL, 0, 0); + ASSERT_TRUE(ret); + + usleep(100000); + + return true; +} -- 2.7.4 From a718244c631c79952680c6f80de925e3c7c4153c Mon Sep 17 00:00:00 2001 From: "kibak.yoon" Date: Wed, 5 Apr 2017 10:50:34 +0900 Subject: [PATCH 13/16] sensord: add util functions to sensor:utils namepsace - change sensor_type_t to uri - get timestamp - get client name Change-Id: I3aabf426176306b31a61c4da987281f19664ac62 Signed-off-by: kibak.yoon --- src/shared/sensor_utils.cpp | 201 ++++++++++++++++++++++++++++++++++++++++++++ src/shared/sensor_utils.h | 40 +++++++++ 2 files changed, 241 insertions(+) create mode 100644 src/shared/sensor_utils.cpp create mode 100644 src/shared/sensor_utils.h diff --git a/src/shared/sensor_utils.cpp b/src/shared/sensor_utils.cpp new file mode 100644 index 0000000..2b2781f --- /dev/null +++ b/src/shared/sensor_utils.cpp @@ -0,0 +1,201 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 "sensor_utils.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define PATH_MAX 256 + +/* TODO: move and define string type to sensor_type.h */ +static std::map types = { + {UNKNOWN_SENSOR, "http://tizen.org/sensor/unknown"}, + {ALL_SENSOR, "http://tizen.org/sensor/all"}, + {ACCELEROMETER_SENSOR, "http://tizen.org/sensor/accelerometer"}, + {GRAVITY_SENSOR, "http://tizen.org/sensor/gravity"}, + {LINEAR_ACCEL_SENSOR, "http://tizen.org/sensor/linear_accel"}, + {GEOMAGNETIC_SENSOR, "http://tizen.org/sensor/geomagnetic"}, + {ROTATION_VECTOR_SENSOR, "http://tizen.org/sensor/rotation_vector"}, + {ORIENTATION_SENSOR, "http://tizen.org/sensor/orientation"}, + {GYROSCOPE_SENSOR, "http://tizen.org/sensor/gyroscope"}, + {LIGHT_SENSOR, "http://tizen.org/sensor/light"}, + {PROXIMITY_SENSOR, "http://tizen.org/sensor/proximity"}, + {PRESSURE_SENSOR, "http://tizen.org/sensor/pressure"}, + {ULTRAVIOLET_SENSOR, "http://tizen.org/sensor/ultraviolet"}, + {TEMPERATURE_SENSOR, "http://tizen.org/sensor/temperature"}, + {HUMIDITY_SENSOR, "http://tizen.org/sensor/humidity"}, + {HRM_SENSOR, "http://tizen.org/sensor/heart_rate_monitor"}, + {HRM_LED_GREEN_SENSOR, "http://tizen.org/sensor/hrm.led_green"}, + {HRM_LED_IR_SENSOR, "http://tizen.org/sensor/hrm.led_ir"}, + {HRM_LED_RED_SENSOR, "http://tizen.org/sensor/hrm.led_red"}, + {GYROSCOPE_UNCAL_SENSOR, "http://tizen.org/sensor/gyroscope.uncalibrated"}, + {GEOMAGNETIC_UNCAL_SENSOR, "http://tizen.org/sensor/geomagnetic.uncalibrated"}, + {GYROSCOPE_RV_SENSOR, "http://tizen.org/sensor/rotation_vector.gyroscope"}, + {GEOMAGNETIC_RV_SENSOR, "http://tizen.org/sensor/rotation_vector.geomagnetic"}, + + {HUMAN_PEDOMETER_SENSOR, "http://tizen.org/sensor/human_pedometer"}, + {HUMAN_SLEEP_MONITOR_SENSOR, "http://tizen.org/sensor/human_sleep_monitor"}, + {HUMAN_SLEEP_DETECTOR_SENSOR, "http://tizen.org/sensor/human_sleep_detector"}, + {HUMAN_STRESS_MONITOR_SENSOR, "http://tizen.org/sensor/human_stress_monitor"}, + + {EXERCISE_WALKING_SENSOR, "http://tizen.org/sensor/exercise.walking"}, + {EXERCISE_RUNNING_SENSOR, "http://tizen.org/sensor/exercise.running"}, + {EXERCISE_HIKING_SENSOR, "http://tizen.org/sensor/exercise.hiking"}, + {EXERCISE_CYCLING_SENSOR, "http://tizen.org/sensor/exercise.cycling"}, + {EXERCISE_ELLIPTICAL_SENSOR, "http://tizen.org/sensor/exercise.elliptical"}, + {EXERCISE_INDOOR_CYCLING_SENSOR, "http://tizen.org/sensor/exercise.indoor_cycling"}, + {EXERCISE_ROWING_SENSOR, "http://tizen.org/sensor/exercise.rowing"}, + {EXERCISE_STEPPER_SENSOR, "http://tizen.org/sensor/exercise.stepper"}, + + {EXTERNAL_EXERCISE_SENSOR, "http://tizen.org/sensor/external_exercise"}, + + {FUSION_SENSOR, "http://tizen.org/sensor/fusion"}, + {AUTO_ROTATION_SENSOR, "http://tizen.org/sensor/auto_rotation"}, + {AUTO_BRIGHTNESS_SENSOR, "http://tizen.org/sensor/auto_brightness"}, + + {GESTURE_MOVEMENT_SENSOR, "http://tizen.org/sensor/gesture_movement"}, + {GESTURE_WRIST_UP_SENSOR, "http://tizen.org/sensor/gesture_wrist_up"}, + {GESTURE_WRIST_DOWN_SENSOR, "http://tizen.org/sensor/gesture_wrist_down"}, + {GESTURE_MOVEMENT_STATE_SENSOR, "http://tizen.org/sensor/gesture_movement_state"}, + {GESTURE_FACE_DOWN_SENSOR, "http://tizen.org/sensor/gesture_face_down"}, + + {ACTIVITY_TRACKER_SENSOR, "http://tizen.org/sensor/activity_tracker"}, + {ACTIVITY_LEVEL_MONITOR_SENSOR, "http://tizen.org/sensor/activity_level_monitor"}, + {GPS_BATCH_SENSOR, "http://tizen.org/sensor/gps_batch"}, + + {HRM_CTRL_SENSOR, "http://tizen.org/sensor/hrm_ctrl"}, + + {WEAR_STATUS_SENSOR, "http://tizen.org/sensor/wear_status"}, + {WEAR_ON_MONITOR_SENSOR, "http://tizen.org/sensor/wear_on_monitor"}, + {NO_MOVE_DETECTOR_SENSOR, "http://tizen.org/sensor/no_move_detector"}, + {RESTING_HR_SENSOR, "http://tizen.org/sensor/resting_hr"}, + {STEP_LEVEL_MONITOR_SENSOR, "http://tizen.org/sensor/step_level_monitor"}, + {EXERCISE_STANDALONE_SENSOR, "http://tizen.org/sensor/exercise_standalone"}, + {EXERCISE_HR_SENSOR, "http://tizen.org/sensor/exercise_hr"}, + {WORKOUT_SENSOR, "http://tizen.org/sensor/workout"}, + {CYCLE_MONITOR_SENSOR, "http://tizen.org/sensor/cycle_monitor"}, + {STAIR_TRACKER_SENSOR, "http://tizen.org/sensor/stair_tracker"}, + {PRESSURE_INDICATOR_SENSOR, "http://tizen.org/sensor/pressure_indicator"}, + {PRESSURE_ALERT_SENSOR, "http://tizen.org/sensor/pressure_alert"}, + {HR_CALORIE_SENSOR, "http://tizen.org/sensor/hr_calorie"}, + + {CONTEXT_SENSOR, "http://tizen.org/sensor/context"}, + {MOTION_SENSOR, "http://tizen.org/sensor/motion"}, + {PIR_SENSOR, "http://tizen.org/sensor/pir"}, + {PIR_LONG_SENSOR, "http://tizen.org/sensor/pir_long"}, + {DUST_SENSOR, "http://tizen.org/sensor/dust"}, + {THERMOMETER_SENSOR, "http://tizen.org/sensor/thermometer"}, + {PEDOMETER_SENSOR, "http://tizen.org/sensor/pedometer"}, + {FLAT_SENSOR, "http://tizen.org/sensor/flat"}, + {HRM_RAW_SENSOR, "http://tizen.org/sensor/hrm_raw"}, + {TILT_SENSOR, "http://tizen.org/sensor/tilt"}, + {RV_RAW_SENSOR, "http://tizen.org/sensor/rv_raw"}, + {GSR_SENSOR, "http://tizen.org/sensor/gsr"}, + {SIMSENSE_SENSOR, "http://tizen.org/sensor/simsense"}, + {PPG_SENSOR, "http://tizen.org/sensor/ppg"}, +}; + +const char *sensor::utils::get_uri(sensor_type_t type) +{ + auto it = types.find(type); + if (it == types.end()) + return "Unknown Type"; + return it->second; +} + +unsigned long long sensor::utils::get_timestamp(void) +{ + struct timespec t; + clock_gettime(CLOCK_MONOTONIC, &t); + return ((unsigned long long)(t.tv_sec)*1000000000LL + t.tv_nsec) / 1000; +} + +unsigned long long sensor::utils::get_timestamp(timeval *t) +{ + if (!t) + return 0; + + return ((unsigned long long)(t->tv_sec)*1000000LL +t->tv_usec); +} + +#ifdef _DEBUG +bool sensor::utils::get_proc_name(pid_t pid, char *process_name) +{ + FILE *fp; + char buf[NAME_MAX]; + char filename[PATH_MAX]; + + sprintf(filename, "/proc/%d/stat", pid); + fp = fopen(filename, "r"); + + if (fp == NULL) + return false; + + if (fscanf(fp, "%*s (%[^)]", buf) < 1) { + fclose(fp); + return false; + } + + strncpy(process_name, buf, NAME_MAX-1); + process_name[NAME_MAX-1] = '\0'; + fclose(fp); + + return true; +} +#else +bool sensor::utils::get_proc_name(pid_t pid, char *process_name) +{ + char buf[NAME_MAX]; + + if (snprintf(buf, sizeof(buf), "%d process", pid) < 1) { + return false; + } + + strncpy(process_name, buf, NAME_MAX-1); + process_name[NAME_MAX-1] = '\0'; + + return true; +} +#endif + +const char* sensor::utils::get_client_name(void) +{ + const int pid_string_size = 10; + static pid_t pid = -1; + static char client_name[NAME_MAX + pid_string_size]; + + char proc_name[NAME_MAX]; + + if (pid == -1) + { + pid = getpid(); + get_proc_name(pid, proc_name); + snprintf(client_name, sizeof(client_name), "%s(%d)", proc_name, pid); + } + + return client_name; +} diff --git a/src/shared/sensor_utils.h b/src/shared/sensor_utils.h new file mode 100644 index 0000000..c6ab64d --- /dev/null +++ b/src/shared/sensor_utils.h @@ -0,0 +1,40 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 __SENSOR_UTILS_H__ +#define __SENSOR_UTILS_H__ + +#include +#include + +namespace sensor { + +namespace utils { + const char *get_uri(sensor_type_t type); + + unsigned long long get_timestamp(void); + unsigned long long get_timestamp(timeval *t); + + const char* get_client_name(void); + bool get_proc_name(pid_t pid, char *process_name); +} + +} + +#endif /* __SENSOR_UTILS_H__ */ -- 2.7.4 From 850ec974bbe07d4785a1ff002132544b1c145fcb Mon Sep 17 00:00:00 2001 From: "kibak.yoon" Date: Wed, 5 Apr 2017 12:21:11 +0900 Subject: [PATCH 14/16] sensord: clean up sensor_info class to support URI as name - sensor_info class has sensor information and can support serialize/deserialize information between client and server. - URI(type and name) is supported - TODO-LIST - some information is redundant or requires a clear distinction Change-Id: I3f40376f37cccbb003d865b7558b5fc55a3b141f Signed-off-by: kibak.yoon --- include/sensor_types.h | 3 + src/shared/sensor_info.cpp | 213 ++++++++++++++++++++++++++------------------- src/shared/sensor_info.h | 59 ++++++++----- 3 files changed, 160 insertions(+), 115 deletions(-) diff --git a/include/sensor_types.h b/include/sensor_types.h index 5062062..5266450 100644 --- a/include/sensor_types.h +++ b/include/sensor_types.h @@ -57,6 +57,9 @@ extern "C" #define MICROSECONDS(tv) ((tv.tv_sec * 1000000ll) + tv.tv_usec) +#define SENSOR_UNKNOWN_TYPE "http://tizen.org/sensor/unknown" +#define SENSOR_UNKNOWN_NAME "Unknown" + typedef int64_t sensor_id_t; typedef void *sensor_t; diff --git a/src/shared/sensor_info.cpp b/src/shared/sensor_info.cpp index 2a2ca83..f634c50 100644 --- a/src/shared/sensor_info.cpp +++ b/src/shared/sensor_info.cpp @@ -1,7 +1,7 @@ /* * sensord * - * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * Copyright (c) 2017 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,38 +17,93 @@ * */ -#include +#include "sensor_info.h" + +#include #include #include -#include #include -using std::vector; -using std::string; +#include "sensor_utils.h" + +using namespace sensor; + +sensor_info::sensor_info() +: m_type(UNKNOWN_SENSOR) +, m_type_uri(SENSOR_UNKNOWN_TYPE) +, m_uri(SENSOR_UNKNOWN_NAME) +, m_model(SENSOR_UNKNOWN_NAME) +, m_vendor(SENSOR_UNKNOWN_NAME) +, m_min_range(0) +, m_max_range(0) +, m_resolution(0) +, m_min_interval(0) +, m_max_batch_count(0) +, m_wakeup_supported(false) +, m_permission(SENSOR_PERMISSION_STANDARD) /* TODO: change it to string */ +{ +} + +sensor_info::sensor_info(const sensor_info &info) +: m_type(info.m_type) +, m_type_uri(info.m_type_uri) +, m_uri(info.m_uri) +, m_model(info.m_model) +, m_vendor(info.m_vendor) +, m_min_range(info.m_min_range) +, m_max_range(info.m_max_range) +, m_resolution(info.m_resolution) +, m_min_interval(info.m_min_interval) +, m_max_batch_count(info.m_max_batch_count) +, m_wakeup_supported(info.m_wakeup_supported) +, m_permission(SENSOR_PERMISSION_STANDARD) +{ +} + +sensor_info::sensor_info(const sensor_info_t &info) +{ + /* TODO: HAL should change name from single name to URI */ + const char *type_uri = sensor::utils::get_uri((sensor_type_t)info.type); + std::string name(type_uri); + name.append("/").append(info.name); + + set_type((sensor_type_t)info.type); + set_type_uri(type_uri); + set_uri(name.c_str()); + set_model(info.model_name); + set_vendor(info.vendor); + set_min_range(info.min_range); + set_max_range(info.max_range); + set_resolution(info.resolution); + set_min_interval(info.min_interval); + set_max_batch_count(info.max_batch_count); + set_wakeup_supported(info.wakeup_supported); + set_permission(SENSOR_PERMISSION_STANDARD); +} sensor_type_t sensor_info::get_type(void) { return m_type; } -sensor_id_t sensor_info::get_id(void) +std::string &sensor_info::get_type_uri(void) { - return m_id; + return m_type_uri; } -sensor_privilege_t sensor_info::get_privilege(void) +std::string &sensor_info::get_uri(void) { - return m_privilege; + return m_uri; } -const char* sensor_info::get_name(void) +std::string &sensor_info::get_model(void) { - return m_name.c_str(); + return m_model; } -const char* sensor_info::get_vendor(void) +std::string &sensor_info::get_vendor(void) { - return m_vendor.c_str(); + return m_vendor; } float sensor_info::get_min_range(void) @@ -71,32 +126,19 @@ int sensor_info::get_min_interval(void) return m_min_interval; } -int sensor_info::get_fifo_count(void) -{ - return m_fifo_count; -} - int sensor_info::get_max_batch_count(void) { return m_max_batch_count; } -unsigned int sensor_info::get_supported_event(void) -{ - return m_supported_event; -} - -bool sensor_info::is_supported_event(unsigned int event) +bool sensor_info::is_wakeup_supported(void) { - if (event != m_supported_event) - return false; - - return true; + return m_wakeup_supported; } -bool sensor_info::is_wakeup_supported(void) +sensor_permission_t sensor_info::get_permission(void) { - return m_wakeup_supported; + return m_permission; } void sensor_info::set_type(sensor_type_t type) @@ -104,19 +146,19 @@ void sensor_info::set_type(sensor_type_t type) m_type = type; } -void sensor_info::set_id(sensor_id_t id) +void sensor_info::set_type_uri(const char *type_uri) { - m_id = id; + m_type_uri = type_uri; } -void sensor_info::set_privilege(sensor_privilege_t privilege) +void sensor_info::set_uri(const char *name) { - m_privilege = privilege; + m_uri = name; } -void sensor_info::set_name(const char *name) +void sensor_info::set_model(const char *model) { - m_name = name; + m_model = model; } void sensor_info::set_vendor(const char *vendor) @@ -144,109 +186,98 @@ void sensor_info::set_min_interval(int min_interval) m_min_interval = min_interval; } -void sensor_info::set_fifo_count(int fifo_count) -{ - m_fifo_count = fifo_count; -} - void sensor_info::set_max_batch_count(int max_batch_count) { m_max_batch_count = max_batch_count; } -void sensor_info::set_supported_event(unsigned int event) +void sensor_info::set_wakeup_supported(bool supported) { - m_supported_event = event; + m_wakeup_supported = supported; } -void sensor_info::set_wakeup_supported(bool supported) +void sensor_info::set_permission(sensor_permission_t permission) { - m_wakeup_supported = supported; + m_permission = permission; } -void sensor_info::get_raw_data(raw_data_t &data) +void sensor_info::serialize(raw_data_t &data) { - put(data, (int) m_type); - put(data, m_id); - put(data, (int) m_privilege); - put(data, m_name); + put(data, m_type); + put(data, m_type_uri); + put(data, m_uri); + put(data, m_model); put(data, m_vendor); put(data, m_min_range); put(data, m_max_range); put(data, m_resolution); put(data, m_min_interval); - put(data, m_fifo_count); put(data, m_max_batch_count); - put(data, m_supported_event); put(data, m_wakeup_supported); + put(data, (int)m_permission); } -void sensor_info::set_raw_data(const char *data, int data_len) +void sensor_info::deserialize(const char *data, int data_len) { + int permission; + int type; + raw_data_t raw_data(&data[0], &data[data_len]); + auto it = raw_data.begin(); + it = get(it, type); + m_type = (sensor_type_t)type; + + it = get(it, m_type_uri); + it = get(it, m_uri); + it = get(it, m_model); + it = get(it, m_vendor); + it = get(it, m_min_range); + it = get(it, m_max_range); + it = get(it, m_resolution); + it = get(it, m_min_interval); + it = get(it, m_max_batch_count); + it = get(it, m_wakeup_supported); - auto it_r_data = raw_data.begin(); - - int type, privilege; - int64_t id; - - it_r_data = get(it_r_data, type); - m_type = (sensor_type_t) type; - it_r_data = get(it_r_data, id); - m_id = (sensor_id_t) id; - it_r_data = get(it_r_data, privilege); - m_privilege = (sensor_privilege_t) privilege; - it_r_data = get(it_r_data, m_name); - it_r_data = get(it_r_data, m_vendor); - it_r_data = get(it_r_data, m_min_range); - it_r_data = get(it_r_data, m_max_range); - it_r_data = get(it_r_data, m_resolution); - it_r_data = get(it_r_data, m_min_interval); - it_r_data = get(it_r_data, m_fifo_count); - it_r_data = get(it_r_data, m_max_batch_count); - it_r_data = get(it_r_data, m_supported_event); - it_r_data = get(it_r_data, m_wakeup_supported); + it = get(it, permission); + m_permission = (sensor_permission_t)permission; } void sensor_info::show(void) { - _I("Type = %d", m_type); - _I("ID = %#llx", (int64_t)m_id); - _I("Privilege = %d", (int)m_privilege); - _I("Name = %s", m_name.c_str()); + _I("Type = %s", m_type_uri.c_str()); + _I("Name = %s", m_uri.c_str()); + _I("Model = %s", m_model.c_str()); _I("Vendor = %s", m_vendor.c_str()); _I("Min_range = %f", m_min_range); _I("Max_range = %f", m_max_range); _I("Resolution = %f", m_resolution); _I("Min_interval = %d", m_min_interval); - _I("Fifo_count = %d", m_fifo_count); _I("Max_batch_count = %d", m_max_batch_count); - _I("Supported_event = %#x", m_supported_event); _I("Wakeup_supported = %d", m_wakeup_supported); + _I("Privilege = %d", (int)m_permission); } void sensor_info::clear(void) { m_type = UNKNOWN_SENSOR; - m_id = -1; - m_privilege = SENSOR_PRIVILEGE_PUBLIC; - m_name.clear(); + m_type_uri.clear(); + m_uri.clear(); + m_model.clear(); m_vendor.clear(); m_min_range = 0.0f; m_max_range = 0.0f; m_resolution = 0.0f; m_min_interval = 0; - m_fifo_count = 0; m_max_batch_count = 0; - m_supported_event = 0; m_wakeup_supported = false; + m_permission = SENSOR_PERMISSION_STANDARD; } void sensor_info::put(raw_data_t &data, int value) { char buffer[sizeof(value)]; - int *temp = (int *)buffer; + int *temp = reinterpret_cast(buffer); *temp = value; copy(&buffer[0], &buffer[sizeof(buffer)], back_inserter(data)); @@ -256,7 +287,7 @@ void sensor_info::put(raw_data_t &data, unsigned int value) { char buffer[sizeof(value)]; - unsigned int *temp = (unsigned int *)buffer; + unsigned int *temp = reinterpret_cast(buffer); *temp = value; copy(&buffer[0], &buffer[sizeof(buffer)], back_inserter(data)); @@ -266,7 +297,7 @@ void sensor_info::put(raw_data_t &data, int64_t value) { char buffer[sizeof(value)]; - int64_t *temp = (int64_t *) buffer; + int64_t *temp = reinterpret_cast(buffer); *temp = value; copy(&buffer[0], &buffer[sizeof(buffer)], back_inserter(data)); @@ -276,13 +307,13 @@ void sensor_info::put(raw_data_t &data, float value) { char buffer[sizeof(value)]; - float *temp = (float *) buffer; + float *temp = reinterpret_cast(buffer); *temp = value; copy(&buffer[0], &buffer[sizeof(buffer)], back_inserter(data)); } -void sensor_info::put(raw_data_t &data, string &value) +void sensor_info::put(raw_data_t &data, std::string &value) { put(data, (int) value.size()); @@ -327,7 +358,7 @@ raw_data_iterator sensor_info::get(raw_data_iterator it, float &value) return it + sizeof(value); } -raw_data_iterator sensor_info::get(raw_data_iterator it, string &value) +raw_data_iterator sensor_info::get(raw_data_iterator it, std::string &value) { int len; diff --git a/src/shared/sensor_info.h b/src/shared/sensor_info.h index 8a50d64..4fbabe8 100644 --- a/src/shared/sensor_info.h +++ b/src/shared/sensor_info.h @@ -1,7 +1,7 @@ /* * sensord * - * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * Copyright (c) 2017 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,68 +17,76 @@ * */ -#ifndef _SENSOR_INFO_H_ -#define _SENSOR_INFO_H_ +#ifndef __SENSOR_INFO_H__ +#define __SENSOR_INFO_H__ #include -#include #include #include +#include +#include + +namespace sensor { typedef std::vector raw_data_t; typedef raw_data_t::iterator raw_data_iterator; +/* TODO: builder */ class sensor_info { public: + sensor_info(); + sensor_info(const sensor_info &info); + sensor_info(const sensor_info_t &info); + + /* TODO: it would be better to get_type() returns type(URI) */ sensor_type_t get_type(void); - sensor_id_t get_id(void); - sensor_privilege_t get_privilege(void); - const char* get_name(void); - const char* get_vendor(void); + std::string &get_type_uri(void); + std::string &get_uri(void); + std::string &get_model(void); + std::string & get_vendor(void); float get_min_range(void); float get_max_range(void); float get_resolution(void); int get_min_interval(void); - int get_fifo_count(void); int get_max_batch_count(void); - unsigned int get_supported_event(void); - bool is_supported_event(unsigned int event); bool is_wakeup_supported(void); + sensor_permission_t get_permission(void); + /* TODO: it would be better to get_type() returns type(URI) */ void set_type(sensor_type_t type); - void set_id(sensor_id_t id); - void set_privilege(sensor_privilege_t privilege); - void set_name(const char *name); + void set_type_uri(const char *type_uri); + void set_uri(const char *name); + void set_model(const char *name); void set_vendor(const char *vendor); void set_min_range(float min_range); void set_max_range(float max_range); void set_resolution(float resolution); void set_min_interval(int min_interval); - void set_fifo_count(int fifo_count); void set_max_batch_count(int max_batch_count); - void set_supported_event(unsigned int event); void set_wakeup_supported(bool supported); + void set_permission(sensor_permission_t permission); void clear(void); - void get_raw_data(raw_data_t &data); - void set_raw_data(const char *data, int data_len); + void serialize(raw_data_t &data); + void deserialize(const char *data, int data_len); void show(void); + private: sensor_type_t m_type; - sensor_id_t m_id; - sensor_privilege_t m_privilege; - std::string m_name; + std::string m_type_uri; + std::string m_uri; + std::string m_model; std::string m_vendor; float m_min_range; float m_max_range; float m_resolution; int m_min_interval; - int m_fifo_count; int m_max_batch_count; - unsigned int m_supported_event; bool m_wakeup_supported; + sensor_permission_t m_permission; + /* TODO: use template */ void put(raw_data_t &data, int value); void put(raw_data_t &data, unsigned int value); void put(raw_data_t &data, int64_t value); @@ -86,6 +94,7 @@ private: void put(raw_data_t &data, std::string &value); void put(raw_data_t &data, bool value); + /* TODO: use template */ raw_data_iterator get(raw_data_iterator it, int &value); raw_data_iterator get(raw_data_iterator it, unsigned int &value); raw_data_iterator get(raw_data_iterator it, int64_t &value); @@ -94,4 +103,6 @@ private: raw_data_iterator get(raw_data_iterator it, bool &value); }; -#endif /* _SENSOR_INFO_H_ */ +} + +#endif /* __SENSOR_INFO_H__ */ -- 2.7.4 From c5b5c233520c5c4246ca257dd4a7fe3a5b0472c6 Mon Sep 17 00:00:00 2001 From: "kibak.yoon" Date: Wed, 5 Apr 2017 13:06:01 +0900 Subject: [PATCH 15/16] sensord: api: add skeleton code of internal apis - sensor_manager can stores and manages all of sensors. - sensor_listener can listen sensor event and modify sensor configuation (interval, option, batch_latency, attributes and so on) - rename client.cpp to sensor_internal.cpp Change-Id: I15b74b777ba70d9c7b7d7a2c597fabf91f259b2c Signed-off-by: kibak.yoon --- src/client/{client.cpp => sensor_internal.cpp} | 0 src/client/sensor_listener.cpp | 201 +++++++++++++++++++++++++ src/client/sensor_listener.h | 95 ++++++++++++ src/client/sensor_manager.cpp | 148 ++++++++++++++++++ src/client/sensor_manager.h | 82 ++++++++++ 5 files changed, 526 insertions(+) rename src/client/{client.cpp => sensor_internal.cpp} (100%) create mode 100644 src/client/sensor_listener.cpp create mode 100644 src/client/sensor_listener.h create mode 100644 src/client/sensor_manager.cpp create mode 100644 src/client/sensor_manager.h diff --git a/src/client/client.cpp b/src/client/sensor_internal.cpp similarity index 100% rename from src/client/client.cpp rename to src/client/sensor_internal.cpp diff --git a/src/client/sensor_listener.cpp b/src/client/sensor_listener.cpp new file mode 100644 index 0000000..83145ef --- /dev/null +++ b/src/client/sensor_listener.cpp @@ -0,0 +1,201 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 "sensor_listener.h" + +#include +#include +#include +#include +#include + +using namespace sensor; + +class listener_handler : public ipc::channel_handler +{ +public: + listener_handler(sensor_listener *listener) + : m_listener(listener) + {} + void connected(ipc::channel *ch) {} + void disconnected(ipc::channel *ch) {} + void read(ipc::channel *ch, ipc::message &msg) {} + void read_complete(ipc::channel *ch) {} + void error_caught(ipc::channel *ch, int error) {} + +private: + sensor_listener *m_listener; +}; + +sensor_listener::sensor_listener(sensor_t sensor) +: m_id(0) +, m_sensor(reinterpret_cast(sensor)) +, m_client(NULL) +, m_channel(NULL) +, m_handler(NULL) +, m_evt_handler(NULL) +, m_acc_handler(NULL) +, m_connected(false) +, m_started(false) +{ + init(); +} + +sensor_listener::~sensor_listener() +{ + deinit(); +} + +bool sensor_listener::init(void) +{ + return true; +} + +void sensor_listener::deinit(void) +{ +} + +int sensor_listener::get_id(void) +{ + return m_id; +} + +sensor_t sensor_listener::get_sensor(void) +{ + return static_cast(m_sensor); +} + +void sensor_listener::restore(void) +{ + _D("Restored listener[%d]", get_id()); +} + +bool sensor_listener::connect(void) +{ + _I("Listener ID[%d]", get_id()); + + return true; +} + +void sensor_listener::disconnect(void) +{ + _I("Disconnected[%d]", get_id()); +} + +bool sensor_listener::is_connected(void) +{ + return m_connected.load(); +} + +ipc::channel_handler *sensor_listener::get_event_handler(void) +{ + return m_evt_handler; +} + +void sensor_listener::set_event_handler(ipc::channel_handler *handler) +{ + m_evt_handler = handler; +} + +void sensor_listener::unset_event_handler(void) +{ + delete m_evt_handler; + m_evt_handler = NULL; +} + +ipc::channel_handler *sensor_listener::get_accuracy_handler(void) +{ + return m_acc_handler; +} + +void sensor_listener::set_accuracy_handler(ipc::channel_handler *handler) +{ + m_acc_handler = handler; +} + +void sensor_listener::unset_accuracy_handler(void) +{ + m_acc_handler = NULL; +} + +int sensor_listener::start(void) +{ + return OP_ERROR; +} + +int sensor_listener::stop(void) +{ + return OP_ERROR; +} + +int sensor_listener::get_interval(void) +{ + return OP_ERROR; +} + +int sensor_listener::get_max_batch_latency(void) +{ + return OP_ERROR; +} + +int sensor_listener::get_pause_policy(void) +{ + return OP_ERROR; +} + +int sensor_listener::get_passive_mode(void) +{ + return OP_ERROR; +} + +int sensor_listener::set_interval(unsigned int interval) +{ + return OP_ERROR; +} + +int sensor_listener::set_max_batch_latency(unsigned int max_batch_latency) +{ + return OP_ERROR; +} + +int sensor_listener::set_passive_mode(bool passive) +{ + return OP_ERROR; +} + +int sensor_listener::flush(void) +{ + return OP_ERROR; +} + +int sensor_listener::set_attribute(int attribute, int value) +{ + return OP_ERROR; +} + +int sensor_listener::set_attribute(int attribute, const char *value, int len) +{ + return OP_ERROR; +} + +int sensor_listener::get_sensor_data(sensor_data_t *data) +{ + return OP_ERROR; +} + diff --git a/src/client/sensor_listener.h b/src/client/sensor_listener.h new file mode 100644 index 0000000..ea30092 --- /dev/null +++ b/src/client/sensor_listener.h @@ -0,0 +1,95 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 __SENSOR_LISTENER_H__ +#define __SENSOR_LISTENER_H__ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace sensor { + +class sensor_listener { +public: + sensor_listener(sensor_t sensor); + virtual ~sensor_listener(); + + int get_id(void); + sensor_t get_sensor(void); + + ipc::channel_handler *get_event_handler(void); + ipc::channel_handler *get_accuracy_handler(void); + + /* TODO: modify the listener so that it can register multiple handlers(1:n) */ + void set_event_handler(ipc::channel_handler *handler); + void set_accuracy_handler(ipc::channel_handler *handler); + + void unset_event_handler(void); + void unset_accuracy_handler(void); + + int start(void); + int stop(void); + + int get_interval(void); + int get_max_batch_latency(void); + int get_pause_policy(void); + int get_passive_mode(void); + + int set_interval(unsigned int interval); + int set_max_batch_latency(unsigned int max_batch_latency); + int set_passive_mode(bool passive); + int set_attribute(int attribute, int value); + int set_attribute(int attribute, const char *value, int len); + + int get_sensor_data(sensor_data_t *data); + int flush(void); + + void restore(void); + +private: + bool init(void); + void deinit(void); + + bool connect(void); + void disconnect(void); + bool is_connected(void); + + int m_id; + sensor_info *m_sensor; + + ipc::ipc_client *m_client; + ipc::channel *m_channel; + ipc::channel_handler *m_handler; + ipc::channel_handler *m_evt_handler; + ipc::channel_handler *m_acc_handler; + ipc::event_loop m_loop; + std::atomic m_connected; + std::atomic m_started; + std::map m_attributes; +}; + +} + +#endif /* __SENSOR_LISTENER_H__ */ diff --git a/src/client/sensor_manager.cpp b/src/client/sensor_manager.cpp new file mode 100644 index 0000000..3a4742b --- /dev/null +++ b/src/client/sensor_manager.cpp @@ -0,0 +1,148 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 "sensor_manager.h" + +#include +#include +#include +#include +#include +#include +#include + +using namespace sensor; + +class manager_handler : public ipc::channel_handler +{ +public: + manager_handler(sensor_manager *manager) + : m_manager(manager) + {} + void connected(ipc::channel *ch) {} + void disconnected(ipc::channel *ch) {} + void read(ipc::channel *ch, ipc::message &msg) {} + void read_complete(ipc::channel *ch) {} + void error_caught(ipc::channel *ch, int error) {} + +private: + sensor_manager *m_manager; +}; + +sensor_manager::sensor_manager() +: m_client(NULL) +, m_handler(NULL) +, m_channel(NULL) +, m_connected(false) +{ + init(); +} + +sensor_manager::~sensor_manager() +{ + deinit(); +} + +int sensor_manager::get_sensor(sensor_type_t type, sensor_t *sensor) +{ + return OP_ERROR; +} + +int sensor_manager::get_sensors(sensor_type_t type, sensor_t **list, int *count) +{ + return OP_ERROR; +} + +int sensor_manager::get_sensor(const char *uri, sensor_t *sensor) +{ + return OP_ERROR; +} + +int sensor_manager::get_sensors(const char *uri, sensor_t **list, int *count) +{ + return OP_ERROR; +} + +bool sensor_manager::is_supported(sensor_t sensor) +{ + return false; +} + +bool sensor_manager::is_supported(const char *uri) +{ + return false; +} + +bool sensor_manager::init(void) +{ + return true; +} + +void sensor_manager::deinit(void) +{ +} + +bool sensor_manager::connect_channel(void) +{ + _D("Connected"); + return true; +} + +bool sensor_manager::connect(void) +{ + return false; +} + +void sensor_manager::disconnect(void) +{ + _D("Disconnected"); +} + +bool sensor_manager::is_connected(void) +{ + return m_connected.load(); +} + +void sensor_manager::restore(void) +{ + _D("Restored manager"); +} + +void sensor_manager::decode_sensors(const char *buf, std::vector &infos) +{ + int count = 0; + _D("Sensor count : %d", count); +} + +bool sensor_manager::get_sensors_internal(void) +{ + return true; +} + +sensor_info *sensor_manager::get_info(const char *uri) +{ + return NULL; +} + +std::vector sensor_manager::get_infos(const char *uri) +{ + std::vector infos; + return infos; +} + diff --git a/src/client/sensor_manager.h b/src/client/sensor_manager.h new file mode 100644 index 0000000..35ae863 --- /dev/null +++ b/src/client/sensor_manager.h @@ -0,0 +1,82 @@ +/* + * sensord + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * + * 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 __SENSOR_MANAGER_H__ +#define __SENSOR_MANAGER_H__ + +#include +#include +#include +#include +#include +#include + +#include "sensor_internal.h" + +namespace sensor { + +class sensor_manager { +public: + sensor_manager(); + virtual ~sensor_manager(); + + bool connect(void); + void disconnect(void); + + int get_sensor(sensor_type_t type, sensor_t *sensor); + int get_sensors(sensor_type_t type, sensor_t **list, int *count); + int get_sensor(const char *uri, sensor_t *sensor); + int get_sensors(const char *uri, sensor_t **list, int *count); + + bool is_supported(sensor_t sensor); + bool is_supported(const char *uri); + + void restore(void); + + /* TODO: register sensor_provider by using manager */ + /* int register_sensor(sensor_provider *provider); */ + /* int unregister_sensor(const char *uri) */ + +private: + typedef std::vector sensor_infos_t; + + bool init(void); + void deinit(void); + + bool connect_channel(void); + bool is_connected(void); + + void decode_sensors(const char *buf, std::vector &infos); + bool get_sensors_internal(void); + + sensor_info *get_info(const char *uri); + std::vector get_infos(const char *uri); + + ipc::ipc_client *m_client; + ipc::channel_handler *m_handler; + ipc::channel *m_channel; + ipc::event_loop m_loop; + std::atomic m_connected; + + sensor_infos_t m_infos; +}; + +} + +#endif /* __SENSOR_MANAGER_H__ */ -- 2.7.4 From f192807171708e30d467c3a11cea4855f6bcd947 Mon Sep 17 00:00:00 2001 From: "kibak.yoon" Date: Wed, 5 Apr 2017 13:50:49 +0900 Subject: [PATCH 16/16] sensor: api: implement internal api using classes - check invalid parameters. - call proper operations/functions. Change-Id: I61b9813a3f77cfd116a8ea72ee417f4cb7356640 Signed-off-by: kibak.yoon --- src/client/sensor_internal.cpp | 532 +++++++++++++++++++++++++++++------------ 1 file changed, 373 insertions(+), 159 deletions(-) diff --git a/src/client/sensor_internal.cpp b/src/client/sensor_internal.cpp index 0864b14..f9b2698 100644 --- a/src/client/sensor_internal.cpp +++ b/src/client/sensor_internal.cpp @@ -17,184 +17,270 @@ * */ -#include "sensor_internal.h" -#include +#include +#include +#include + +#include +#include +#include #include +#include + +#define CONVERT_OPTION_PAUSE_POLICY(option) ((option) ^ 0b11) + +using namespace sensor; + +class sensor_event_handler : public ipc::channel_handler +{ +public: + sensor_event_handler(sensor_t sensor, sensor_cb_t cb, void *user_data) + : m_sensor(reinterpret_cast(sensor)) + , m_cb(cb) + , m_user_data(user_data) + {} + + void connected(ipc::channel *ch) {} + void disconnected(ipc::channel *ch) {} + void read(ipc::channel *ch, ipc::message &msg) + { + int event_type; + sensor_data_t *data; + + data = reinterpret_cast(msg.body()); + event_type = CONVERT_TYPE_EVENT(m_sensor->get_type()); + + m_cb(m_sensor, event_type, data, m_user_data); + } + + void read_complete(ipc::channel *ch) {} + void error_caught(ipc::channel *ch, int error) {} + +private: + sensor_info *m_sensor; + sensor_cb_t m_cb; + void *m_user_data; +}; + +class sensor_accuracy_handler : public ipc::channel_handler +{ +public: + sensor_accuracy_handler(sensor_t sensor, sensor_accuracy_changed_cb_t cb, void *user_data) + : m_sensor(reinterpret_cast(sensor)) + , m_cb(cb) + , m_user_data(user_data) + {} + + void connected(ipc::channel *ch) {} + void disconnected(ipc::channel *ch) {} + void read(ipc::channel *ch, ipc::message &msg) + { + sensor_data_t *data; + data = reinterpret_cast(msg.body()); + + m_cb(m_sensor, data->timestamp, data->accuracy, m_user_data); + } + + void read_complete(ipc::channel *ch) {} + void error_caught(ipc::channel *ch, int error) {} + +private: + sensor_info *m_sensor; + sensor_accuracy_changed_cb_t m_cb; + void *m_user_data; +}; + +static sensor::sensor_manager manager; +static std::unordered_map listeners; /* * TO-DO-LIST: - * 1. restore session - * 1.1 close socket - * 1.2 listener : start, interval, batch latency, attributes - * 2. power save option / lcd vconf : move to server - * 3. clean up data - * 4. thread-safe : ipc_client - * 5. client-id - * 6. cmd_hello - * 7. stop : unset interval, batch - * 8. get sensor list + * 1. power save option / lcd vconf : move to server + * 2. thread-safe : ipc_client */ API int sensord_get_sensors(sensor_type_t type, sensor_t **list, int *count) { - /* - * 1. get sensor list() - * 2. if sensor list is empty, return -ENODATA - * 3. if id is -EACCESS, return -EACCESS (except ALL_SENSOR) - * 4. list : memory allocation - * 5. return list, count - */ + int ret = OP_ERROR; + + retvm_if((!list || !count), -EINVAL, + "Invalid parameter[%#x, %#x]", list, count); + retvm_if(!manager.connect(), -EIO, "Failed to connect"); + + ret = manager.get_sensors(type, list, count); + retv_if(ret < 0, ret); return OP_SUCCESS; } API int sensord_get_default_sensor(sensor_type_t type, sensor_t *sensor) { - /* - * 1. get sensor list() - * 2. if there is no sensor, return -ENODATA - * 3. if id is -EACCESS, return -EACCESS - * 4. if SENSOR_ALL, ??? - * 5. return sensor - */ + int ret = OP_ERROR; + + retvm_if(!sensor, -EPERM, "Invalid parameter[%#x]", sensor); + retvm_if(!manager.connect(), -EIO, "Failed to connect"); + + ret = manager.get_sensor(type, sensor); + retv_if(ret < 0, ret); return OP_SUCCESS; } API bool sensord_get_type(sensor_t sensor, sensor_type_t *type) { - /* - * 1. check parameter - * 2. if there is no sensor, return false - */ + retvm_if(!type, false, "Invalid parameter[%#x]", type); + retvm_if(!manager.connect(), false, "Failed to connect"); + retvm_if(!manager.is_supported(sensor), false, + "Invalid sensor[%#x]", sensor); + + *type = static_cast(sensor)->get_type(); return true; } API const char* sensord_get_name(sensor_t sensor) { - /* - * 1. if there is no sensor, return NULL - */ + retvm_if(!manager.connect(), NULL, "Failed to connect"); + retvm_if(!manager.is_supported(sensor), NULL, + "Invalid sensor[%#x]", sensor); - return NULL; + return static_cast(sensor)->get_uri().c_str(); } API const char* sensord_get_vendor(sensor_t sensor) { - /* - * 1. if there is no sensor, return NULL - */ + retvm_if(!manager.connect(), NULL, "Failed to connect"); + retvm_if(!manager.is_supported(sensor), NULL, + "Invalid sensor[%#x]", sensor); - return NULL; + return static_cast(sensor)->get_vendor().c_str(); } API bool sensord_get_privilege(sensor_t sensor, sensor_privilege_t *privilege) { - /* - * 1. check parameter - * 2. if there is no sensor, return false + retvm_if(!manager.connect(), false, "Failed to connect"); + retvm_if(!privilege, false, "Invalid parameter[%#x]", privilege); + retvm_if(!manager.is_supported(sensor), false, + "Invalid sensor[%#x]", sensor); + + /* TODO: + * sensor_permission_t perm = static_cast(sensor)->get_permission(); + * *privilege = static_cast(perm); */ + *privilege = SENSOR_PRIVILEGE_PUBLIC; return true; } API bool sensord_get_min_range(sensor_t sensor, float *min_range) { - /* - * 1. check parameter - * 2. if there is no sensor, return false - */ + retvm_if(!manager.connect(), false, "Failed to connect"); + retvm_if(!min_range, false, "Invalid parameter[%#x]", min_range); + retvm_if(!manager.is_supported(sensor), false, + "Invalid sensor[%#x]", sensor); + + *min_range = static_cast(sensor)->get_min_range(); return true; } API bool sensord_get_max_range(sensor_t sensor, float *max_range) { - /* - * 1. check parameter - * 2. if there is no sensor, return false - */ + retvm_if(!max_range, false, "Invalid parameter[%#x]", max_range); + retvm_if(!manager.connect(), false, "Failed to connect"); + retvm_if(!manager.is_supported(sensor), false, + "Invalid sensor[%#x]", sensor); + + *max_range = static_cast(sensor)->get_max_range(); return true; } API bool sensord_get_resolution(sensor_t sensor, float *resolution) { - /* - * 1. check parameter - * 2. if there is no sensor, return false - */ + retvm_if(!resolution, false, "Invalid parameter[%#x]", resolution); + retvm_if(!manager.connect(), false, "Failed to connect"); + retvm_if(!manager.is_supported(sensor), false, + "Invalid sensor[%#x]", sensor); + + *resolution = static_cast(sensor)->get_resolution(); return true; } API bool sensord_get_min_interval(sensor_t sensor, int *min_interval) { - /* - * 1. check parameter - * 2. if there is no sensor, return false - */ + retvm_if(!min_interval, false, "Invalid parameter[%#x]", min_interval); + retvm_if(!manager.connect(), false, "Failed to connect"); + retvm_if(!manager.is_supported(sensor), false, + "Invalid sensor[%#x]", sensor); + + *min_interval = static_cast(sensor)->get_min_interval(); return true; } API bool sensord_get_fifo_count(sensor_t sensor, int *fifo_count) { - /* - * 1. check parameter - * 2. if there is no sensor, return false - */ + retvm_if(!fifo_count, false, "Invalid parameter[%#x]", fifo_count); + retvm_if(!manager.connect(), false, "Failed to connect"); + retvm_if(!manager.is_supported(sensor), false, + "Invalid sensor[%#x]", sensor); + + *fifo_count = 0; return true; } API bool sensord_get_max_batch_count(sensor_t sensor, int *max_batch_count) { - /* - * 1. check parameter - * 2. if there is no sensor, return false - */ + retvm_if(!max_batch_count, false, "Invalid parameter[%#x]", max_batch_count); + retvm_if(!manager.connect(), false, "Failed to connect"); + retvm_if(!manager.is_supported(sensor), false, + "Invalid sensor[%#x]", sensor); + + *max_batch_count = static_cast(sensor)->get_max_batch_count(); return true; } API bool sensord_is_wakeup_supported(sensor_t sensor) { - /* - * 1. check parameter - * 2. if there is no sensor, return false - */ + retvm_if(!manager.connect(), false, "Failed to connect"); + retvm_if(!manager.is_supported(sensor), false, + "Invalid sensor[%#x]", sensor); - return true; + return static_cast(sensor)->is_wakeup_supported(); } API int sensord_connect(sensor_t sensor) { - /* - * 1. check parameter - * 2. if there is no sensor, return -EPERM - * 3. sensor is already registered(sensor), it doesn't need to connect server - * 4. create integer handle for only this client - * 5. if it is first connection(client), get client id from server - * 6. if it is first connection(client), start sensor event listener - * 7. sensor initialization : stop, pause_all - * 8. if it is first connection(client), send cmd hello - * 9. if cmd hello is failed and it is first connection(client) stop listener, remove id - */ + retvm_if(!manager.connect(), -EIO, "Failed to connect"); + retvm_if(!manager.is_supported(sensor), -EINVAL, + "Invalid sensor[%#x]", sensor); - return 0; + sensor::sensor_listener *listener; + + listener = new(std::nothrow) sensor::sensor_listener(sensor); + retvm_if(!listener, -ENOMEM, "Failed to allocate memory"); + + listeners[listener->get_id()] = listener; + + return listener->get_id(); } API bool sensord_disconnect(int handle) { - /* - * 1. check parameter(check handle???) - * 2. check state of this handle - * 3. if it is on passive mode, unregister event and unset interval/latency - * 4. if it is not stop, stop it - * 5. if there is no active sensor(client), reset id & byebye and stop listener - */ + sensor::sensor_listener *listener; + + auto it = listeners.find(handle); + retvm_if(it == listeners.end(), false, "Invalid handle[%d]", handle); + + listener = it->second; + retvm_if(!listener, false, "Invalid handle[%d]", handle); + + delete listener; + listeners.erase(handle); return true; } @@ -202,148 +288,270 @@ API bool sensord_disconnect(int handle) API bool sensord_register_event(int handle, unsigned int event_type, unsigned int interval, unsigned int max_batch_latency, sensor_cb_t cb, void *user_data) { - /* - * 1. check parameter - * 2. if interval is 0, default interval - * ** if cb is null, how to handle it? - * ** event type is deprecated - */ + sensor::sensor_listener *listener; + int prev_interval; + int prev_max_batch_latency; + sensor_event_handler *handler; + + auto it = listeners.find(handle); + retvm_if(it == listeners.end(), false, "Invalid handle[%d]", handle); + + listener = it->second; + + prev_interval = listener->get_interval(); + prev_max_batch_latency = listener->get_max_batch_latency(); + + if (listener->set_interval(interval) < 0) { + _E("Failed to set interval"); + return false; + } + + if (listener->set_max_batch_latency(max_batch_latency) < 0) { + listener->set_interval(prev_interval); + _E("Failed to set max_batch_latency"); + return false; + } + + handler = new(std::nothrow) sensor_event_handler(listener->get_sensor(), cb, user_data); + if (!handler) { + listener->set_max_batch_latency(prev_max_batch_latency); + listener->set_interval(prev_interval); + _E("Failed to allocate memory"); + return false; + } + + listener->set_event_handler(handler); return true; } API bool sensord_unregister_event(int handle, unsigned int event_type) { - /* - * 1. check parameter - * 2. check previous interval, latency, cb, user_data - * 3. if passive mode is true, set false - * 4. if ret is false, register event - */ + sensor::sensor_listener *listener; + + auto it = listeners.find(handle); + retvm_if(it == listeners.end(), false, "Invalid handle[%d]", handle); + + listener = it->second; + + listener->unset_event_handler(); return true; } API bool sensord_register_accuracy_cb(int handle, sensor_accuracy_changed_cb_t cb, void *user_data) { - /* - * 1. check parameter - */ + sensor::sensor_listener *listener; + sensor_accuracy_handler *handler; + + auto it = listeners.find(handle); + retvm_if(it == listeners.end(), false, "Invalid handle[%d]", handle); + + listener = it->second; + + handler = new(std::nothrow) sensor_accuracy_handler(listener->get_sensor(), cb, user_data); + retvm_if(!handler, false, "Failed to allocate memory"); + + listener->set_accuracy_handler(handler); return true; } API bool sensord_unregister_accuracy_cb(int handle) { - /* - * 1. check parameter - */ + sensor::sensor_listener *listener; + + auto it = listeners.find(handle); + retvm_if(it == listeners.end(), false, "Invalid handle[%d]", handle); + + listener = it->second; + + listener->unset_accuracy_handler(); return true; } API bool sensord_start(int handle, int option) { - /* - * 1. check parameter - * 2. pause = CONVERT_OPTION_PAUSE_POLICY(option) - * 3. start listener - */ + sensor::sensor_listener *listener; + int prev_pause; + int pause; + + auto it = listeners.find(handle); + retvm_if(it == listeners.end(), false, "Invalid handle[%d]", handle); + + listener = it->second; + + pause = CONVERT_OPTION_PAUSE_POLICY(option); + prev_pause = listener->get_pause_policy(); + + if (listener->set_attribute(SENSORD_ATTRIBUTE_PAUSE_POLICY, pause) < 0) { + _E("Failed to set pause policy[%d]", pause); + return false; + } + + if (listener->start() < 0) { + listener->set_attribute(SENSORD_ATTRIBUTE_PAUSE_POLICY, prev_pause); + _E("Failed to start listener"); + return false; + } return true; } API bool sensord_stop(int handle) { - /* - * 1. check parameter - * 2. check sensor state, id - * 2.1. if sensor is already stopped, return true - * 3. stop listener - */ + int ret; + sensor::sensor_listener *listener; - return true; + auto it = listeners.find(handle); + retvm_if(it == listeners.end(), false, "Invalid handle[%d]", handle); + + listener = it->second; + + ret = listener->stop(); + + if (ret == -EAGAIN || ret == OP_SUCCESS) + return true; + + return false; } API bool sensord_change_event_interval(int handle, unsigned int event_type, unsigned int interval) { - /* - * 1. check parameter - * 2. if interval is 0, default interval - * 3. if previous interval is lower than interval, return true - * 4. change interval - */ + sensor::sensor_listener *listener; + + auto it = listeners.find(handle); + retvm_if(it == listeners.end(), false, "Invalid handle[%d]", handle); + + listener = it->second; + + if (listener->set_interval(interval) < 0) { + _E("Failed to set interval to listener"); + return false; + } return true; } API bool sensord_change_event_max_batch_latency(int handle, unsigned int event_type, unsigned int max_batch_latency) { - /* - * 1. check parameter - * 2. if previous interval is lower than interval, return true - * 3. change batch latency - */ + sensor::sensor_listener *listener; + + auto it = listeners.find(handle); + retvm_if(it == listeners.end(), false, "Invalid handle[%d]", handle); + + listener = it->second; + + if (listener->set_max_batch_latency(max_batch_latency) < 0) { + _E("Failed to set max_batch_latency to listener"); + return false; + } return true; } API bool sensord_set_option(int handle, int option) { - /* - * change option, always-on/power save option/lcd off/default - */ + sensor::sensor_listener *listener; + int pause; + + auto it = listeners.find(handle); + retvm_if(it == listeners.end(), false, "Invalid handle[%d]", handle); + + listener = it->second; + + pause = CONVERT_OPTION_PAUSE_POLICY(option); + + if (listener->set_attribute(SENSORD_ATTRIBUTE_PAUSE_POLICY, pause) < 0) { + _E("Failed to set option[%d(%d)] to listener", option, pause); + return false; + } return true; } API int sensord_set_attribute_int(int handle, int attribute, int value) { - /* - * 1. if ATTRIBUTE_PAUSE_POLICY - * 2. if ATTRIBUTE_AXIS_ORIENTATION - * 3. else attribute - */ + sensor::sensor_listener *listener; + + auto it = listeners.find(handle); + retvm_if(it == listeners.end(), -EINVAL, "Invalid handle[%d]", handle); + + listener = it->second; + + if (listener->set_attribute(attribute, value) < 0) { + _E("Failed to set attribute[%d, %d]", attribute, value); + return -EIO; + } return OP_SUCCESS; } API int sensord_set_attribute_str(int handle, int attribute, const char *value, int len) { - /* - * 1. check parameter - * 2. if client id is invalid, return -EPERM - * 3. if there is other problems, return -EPERM - */ + sensor::sensor_listener *listener; + + auto it = listeners.find(handle); + retvm_if(it == listeners.end(), -EINVAL, "Invalid handle[%d]", handle); + + listener = it->second; + + if (listener->set_attribute(attribute, value, len) < 0) { + _E("Failed to set attribute[%d, %s]", attribute, value); + return -EIO; + } return OP_SUCCESS; } API bool sensord_get_data(int handle, unsigned int data_id, sensor_data_t* sensor_data) { - /* - * 1. check parameter - * 2. check sensor state(is it really needed?) - * 3. get data - */ + sensor::sensor_listener *listener; + + auto it = listeners.find(handle); + retvm_if(it == listeners.end(), false, "Invalid handle[%d]", handle); + + listener = it->second; + + if (listener->get_sensor_data(sensor_data) < 0) { + _E("Failed to get sensor data from listener"); + return false; + } return true; } API bool sensord_flush(int handle) { - /* - * 1. check parameter - * 2. check sensor state(is it really needed?) - * 3. flush sensor - */ + sensor::sensor_listener *listener; + + auto it = listeners.find(handle); + retvm_if(it == listeners.end(), false, "Invalid handle[%d]", handle); + + listener = it->second; + + if (listener->flush() < 0) { + _E("Failed to flush sensor"); + return false; + } return true; } API bool sensord_set_passive_mode(int handle, bool passive) { - /* set passive mode*/ + sensor::sensor_listener *listener; + + auto it = listeners.find(handle); + retvm_if(it == listeners.end(), false, "Invalid handle[%d]", handle); + + listener = it->second; + + if (listener->set_passive_mode(passive) < 0) { + _E("Failed to set passive mode"); + return false; + } return true; } @@ -387,7 +595,12 @@ API bool sensord_external_post(int handle, unsigned long long timestamp, const f /* deperecated */ API sensor_t sensord_get_sensor(sensor_type_t type) { - return NULL; + sensor_t sensor; + + if (sensord_get_default_sensor(type, &sensor) < 0) + return NULL; + + return sensor; } /* deprecated */ @@ -417,10 +630,11 @@ API bool sensord_get_supported_event_types(sensor_t sensor, unsigned int **event /* deprecated(BUT it is used in C-API....) */ API bool sensord_is_supported_event_type(sensor_t sensor, unsigned int event_type, bool *supported) { - /* - * 1. check parameter - * 2. if there is no sensor, return false - */ + if (!manager.is_supported(sensor)) + *supported = false; + else + *supported = true; + return true; } -- 2.7.4