diff --git a/app/play/play_core/src/measurement_container.h b/app/play/play_core/src/measurement_container.h index dad5036590..26dbdfca80 100644 --- a/app/play/play_core/src/measurement_container.h +++ b/app/play/play_core/src/measurement_container.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2024 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ #include #include -#include +#include #include #include "continuity_report.h" diff --git a/app/rec/rec_client_core/src/ecal_rec_impl.h b/app/rec/rec_client_core/src/ecal_rec_impl.h index 1c1e42ff15..5b6cba3fc7 100644 --- a/app/rec/rec_client_core/src/ecal_rec_impl.h +++ b/app/rec/rec_client_core/src/ecal_rec_impl.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2024 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,8 +40,7 @@ #include "frame_buffer.h" -#include -#include +#include namespace eCAL { diff --git a/app/rec/rec_client_core/src/frame.h b/app/rec/rec_client_core/src/frame.h index d65d1f2326..144f416b25 100644 --- a/app/rec/rec_client_core/src/frame.h +++ b/app/rec/rec_client_core/src/frame.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ #include #include #include -#include +#include namespace eCAL { diff --git a/app/rec/rec_server_cli/src/ecal_rec_server_cli.cpp b/app/rec/rec_server_cli/src/ecal_rec_server_cli.cpp index 13f15cea6c..a8a1cac59a 100644 --- a/app/rec/rec_server_cli/src/ecal_rec_server_cli.cpp +++ b/app/rec/rec_server_cli/src/ecal_rec_server_cli.cpp @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include #include diff --git a/app/sys/sys_cli/src/commands/command.h b/app/sys/sys_cli/src/commands/command.h index 2ce60c050b..61e3a0b2a0 100644 --- a/app/sys/sys_cli/src/commands/command.h +++ b/app/sys/sys_cli/src/commands/command.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2020 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,7 +26,7 @@ #include #include -#include +#include #ifdef _MSC_VER #pragma warning(push) diff --git a/app/sys/sys_cli/src/commands/helpers.h b/app/sys/sys_cli/src/commands/helpers.h index 77cfb15711..f5e13a6bcc 100644 --- a/app/sys/sys_cli/src/commands/helpers.h +++ b/app/sys/sys_cli/src/commands/helpers.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2020 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,7 +26,7 @@ #include #include -#include +#include #ifdef _MSC_VER #pragma warning(push) diff --git a/app/sys/sys_cli/src/ecalsys_cli.cpp b/app/sys/sys_cli/src/ecalsys_cli.cpp index 24531699c1..5a042a4256 100644 --- a/app/sys/sys_cli/src/ecalsys_cli.cpp +++ b/app/sys/sys_cli/src/ecalsys_cli.cpp @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include diff --git a/ecal/core/CMakeLists.txt b/ecal/core/CMakeLists.txt index 3d3467b353..043a21431e 100644 --- a/ecal/core/CMakeLists.txt +++ b/ecal/core/CMakeLists.txt @@ -61,21 +61,27 @@ if(UNIX) endif() endif() +macro(add_ecal_core_library TARGET_NAME) ###################################### # config ###################################### set(ecal_config_src - src/config/default_configuration.cpp + src/config/default_configuration.cpp + src/config/default_configuration.h src/config/ecal_config.cpp src/config/configuration.cpp src/config/ecal_path_processing.cpp + src/config/ecal_path_processing.h src/types/ecal_custom_data_types.cpp ) if (ECAL_CORE_CONFIGURATION) list(APPEND ecal_config_src src/config/configuration_to_yaml.cpp + src/config/configuration_to_yaml.h src/config/configuration_reader.cpp + src/config/configuration_reader.h src/config/configuration_writer.cpp + src/config/configuration_writer.h ) endif() ###################################### @@ -183,7 +189,9 @@ endif() set(ecal_logging_src src/logging/ecal_log.cpp src/logging/ecal_log_provider.cpp + src/logging/ecal_log_provider.h src/logging/ecal_log_receiver.cpp + src/logging/ecal_log_receiver.h ) ###################################### @@ -206,9 +214,9 @@ if(ECAL_CORE_PUBLISHER) src/pubsub/ecal_publisher.cpp src/pubsub/ecal_publisher_impl.cpp src/pubsub/ecal_publisher_impl.h - src/pubsub/ecal_publisher_v5.cpp src/pubsub/ecal_pubgate.cpp src/pubsub/ecal_pubgate.h + src/v5/pubsub/ecal_publisher.cpp ) endif() @@ -217,9 +225,9 @@ if(ECAL_CORE_SUBSCRIBER) src/pubsub/ecal_subscriber.cpp src/pubsub/ecal_subscriber_impl.cpp src/pubsub/ecal_subscriber_impl.h - src/pubsub/ecal_subscriber_v5.cpp src/pubsub/ecal_subgate.cpp src/pubsub/ecal_subgate.h + src/v5/pubsub/ecal_subscriber.cpp ) endif() @@ -383,17 +391,17 @@ if(ECAL_CORE_SERVICE) src/service/ecal_service_client_impl.cpp src/service/ecal_service_client_impl.h src/service/ecal_service_client_instance.cpp - src/service/ecal_service_client_v5.cpp - src/service/ecal_service_client_v5_impl.cpp - src/service/ecal_service_client_v5_impl.h src/service/ecal_service_server.cpp src/service/ecal_service_server_impl.cpp src/service/ecal_service_server_impl.h - src/service/ecal_service_server_v5.cpp - src/service/ecal_service_server_v5_impl.cpp - src/service/ecal_service_server_v5_impl.h src/service/ecal_service_singleton_manager.cpp src/service/ecal_service_singleton_manager.h + src/v5/service/ecal_service_client.cpp + src/v5/service/ecal_service_client_impl.cpp + src/v5/service/ecal_service_client_impl.h + src/v5/service/ecal_service_server.cpp + src/v5/service/ecal_service_server_impl.cpp + src/v5/service/ecal_service_server_impl.h ) endif() @@ -433,6 +441,7 @@ endif() ###################################### set(ecal_cmn_src src/ecal.cpp + src/ecal_config_internal.h src/ecal_def.h src/ecal_descgate.cpp src/ecal_descgate.h @@ -458,18 +467,55 @@ endif() ###################################### set (ecal_builder_src src/config/builder/logging_attribute_builder.cpp + src/config/builder/logging_attribute_builder.h src/config/builder/registration_attribute_builder.cpp + src/config/builder/registration_attribute_builder.h + + src/logging/config/attributes/ecal_log_provider_attributes.h + src/logging/config/attributes/ecal_log_receiver_attributes.h src/logging/config/builder/udp_attribute_builder.cpp + src/logging/config/builder/udp_attribute_builder.h + src/pubsub/config/builder/reader_attribute_builder.cpp + src/pubsub/config/builder/reader_attribute_builder.h src/pubsub/config/builder/writer_attribute_builder.cpp + src/pubsub/config/builder/writer_attribute_builder.h + + src/readwrite/config/attributes/reader_attributes.h + src/readwrite/config/attributes/writer_attributes.h src/readwrite/config/builder/shm_attribute_builder.cpp + src/readwrite/config/builder/shm_attribute_builder.h src/readwrite/config/builder/tcp_attribute_builder.cpp + src/readwrite/config/builder/tcp_attribute_builder.h src/readwrite/config/builder/udp_attribute_builder.cpp + src/readwrite/config/builder/udp_attribute_builder.h + + src/readwrite/shm/config/attributes/reader_shm_attributes.h + src/readwrite/shm/config/attributes/writer_shm_attributes.h + + src/readwrite/tcp/config/attributes/data_reader_tcp_attributes.h + src/readwrite/tcp/config/attributes/data_writer_tcp_attributes.h + src/readwrite/tcp/config/attributes/tcp_reader_layer_attributes.h src/readwrite/tcp/config/builder/data_reader_tcp_attribute_builder.cpp + src/readwrite/tcp/config/builder/data_reader_tcp_attribute_builder.h + + src/readwrite/udp/config/attributes/reader_udp_attributes.h + src/readwrite/udp/config/attributes/writer_udp_attributes.h src/readwrite/udp/config/builder/udp_attribute_builder.cpp - src/registration/config/builder/udp_shm_attribute_builder.cpp + src/readwrite/udp/config/builder/udp_attribute_builder.h + + src/registration/config/attributes/registration_attributes.h + src/registration/config/attributes/sample_applier_attributes.h src/registration/config/builder/sample_applier_attribute_builder.cpp + src/registration/config/builder/sample_applier_attribute_builder.h + src/registration/config/builder/udp_shm_attribute_builder.cpp + src/registration/config/builder/udp_shm_attribute_builder.h + + src/registration/shm/config/attributes/registration_shm_attributes.h + src/registration/udp/config/attributes/registration_receiver_udp_attributes.h + src/registration/udp/config/attributes/registration_sender_udp_attributes.h src/registration/udp/config/builder/udp_attribute_builder.cpp + src/registration/udp/config/builder/udp_attribute_builder.h ) ###################################### @@ -484,14 +530,20 @@ set(ecal_header_cmn include/ecal/config/subscriber.h include/ecal/config/time.h include/ecal/config/transport_layer.h + include/ecal/pubsub/subscriber.h + include/ecal/pubsub/types.h + include/ecal/pubsub/payload_writer.h + include/ecal/pubsub/publisher.h + include/ecal/service/client.h + include/ecal/service/client_instance.h + include/ecal/service/server.h + include/ecal/service/types.h include/ecal/types/logging.h include/ecal/types/monitoring.h include/ecal/ecal.h include/ecal/ecal_callback.h - include/ecal/ecal_callback_v5.h - include/ecal/ecal_client.h - include/ecal/ecal_client_instance.h - include/ecal/ecal_client_v5.h + include/ecal/v5/ecal_callback.h + include/ecal/v5/ecal_client.h include/ecal/ecal_config.h include/ecal/ecal_core.h include/ecal/ecal_deprecate.h @@ -499,18 +551,14 @@ set(ecal_header_cmn include/ecal/ecal_log.h include/ecal/ecal_log_level.h include/ecal/ecal_os.h - include/ecal/ecal_payload_writer.h include/ecal/ecal_monitoring.h + include/ecal/ecal_namespace.h include/ecal/ecal_process.h include/ecal/ecal_process_severity.h include/ecal/ecal_registration.h - include/ecal/ecal_publisher.h - include/ecal/ecal_publisher_v5.h - include/ecal/ecal_server.h - include/ecal/ecal_server_v5.h - include/ecal/ecal_service_info.h - include/ecal/ecal_subscriber.h - include/ecal/ecal_subscriber_v5.h + include/ecal/v5/ecal_publisher.h + include/ecal/v5/ecal_server.h + include/ecal/v5/ecal_subscriber.h include/ecal/ecal_time.h include/ecal/ecal_timer.h include/ecal/ecal_tlayer.h @@ -552,22 +600,22 @@ set(ecal_sources ${ecal_header_msg} ) -ecal_add_shared_library(${PROJECT_NAME} +ecal_add_shared_library(${TARGET_NAME} ${ecal_sources} ${CMAKE_CURRENT_BINARY_DIR}/include/ecal/ecal_defs.h ) if (ECAL_CORE_CONFIGURATION) - target_compile_definitions(${PROJECT_NAME} PRIVATE ECAL_CORE_CONFIGURATION) + target_compile_definitions(${TARGET_NAME} PRIVATE ECAL_CORE_CONFIGURATION) endif() if(UNIX) set_source_files_properties(src/util/convert_utf.cpp PROPERTIES COMPILE_FLAGS -Wno-implicit-fallthrough) endif() -add_library(eCAL::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) +add_library(eCAL::${TARGET_NAME} ALIAS ${TARGET_NAME}) -target_compile_definitions(${PROJECT_NAME} +target_compile_definitions(${TARGET_NAME} PUBLIC ASIO_STANDALONE ASIO_DISABLE_VISIBILITY @@ -581,7 +629,7 @@ target_compile_definitions(${PROJECT_NAME} ECAL_CORE_IMPORTS ) -set_target_properties(${PROJECT_NAME} +set_target_properties(${TARGET_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden C_VISIBILITY_PRESET hidden @@ -606,45 +654,45 @@ set(ECAL_CORE_FEATURES foreach(CORE_FEATURE ${ECAL_CORE_FEATURES}) if(${CORE_FEATURE}) - target_compile_definitions(${PROJECT_NAME} + target_compile_definitions(${TARGET_NAME} PUBLIC ${CORE_FEATURE}) endif() endforeach() if(ECAL_CORE_CONFIGURATION) - target_link_libraries(${PROJECT_NAME} + target_link_libraries(${TARGET_NAME} PRIVATE yaml-cpp::yaml-cpp ) endif() if(ECAL_CORE_COMMAND_LINE) - target_link_libraries(${PROJECT_NAME} + target_link_libraries(${TARGET_NAME} PRIVATE tclap::tclap ) endif() if(ECAL_CORE_SERVICE) - target_link_libraries(${PROJECT_NAME} + target_link_libraries(${TARGET_NAME} PRIVATE ecal_service ) endif() if(ECAL_CORE_TRANSPORT_TCP) - target_link_libraries(${PROJECT_NAME} + target_link_libraries(${TARGET_NAME} PRIVATE tcp_pubsub::tcp_pubsub ) endif() -target_link_libraries(${PROJECT_NAME} +target_link_libraries(${TARGET_NAME} PRIVATE ecaludp::ecaludp ) -target_include_directories(${PROJECT_NAME} +target_include_directories(${TARGET_NAME} PRIVATE $ $ @@ -655,7 +703,7 @@ target_include_directories(${PROJECT_NAME} $ ) -target_link_libraries(${PROJECT_NAME} +target_link_libraries(${TARGET_NAME} PRIVATE $<$,$>>:dl> $<$,$>,$>>:rt> @@ -672,10 +720,40 @@ target_link_libraries(${PROJECT_NAME} eCAL::ecal-utils ) -set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER core) +set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER core) -ecal_install_shared_library(${PROJECT_NAME}) +ecal_install_shared_library(${TARGET_NAME}) +if(NOT ${CMAKE_VERSION} VERSION_LESS "3.8.0") + source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES + ${ecal_sources} + ) +endif() + +endmacro() + +####################################### +# We now create two libraries +# One of them is a compatibility version that should facilitate easier migration. +# ecal_core, ecal_core_v5. +####################################### + +add_ecal_core_library(${PROJECT_NAME}) +target_compile_definitions(${PROJECT_NAME} + PUBLIC + ECAL_CORE_V5_FUNCTIONALTIY=1 +) + +add_ecal_core_library(core_v5) +target_compile_definitions(core_v5 + PUBLIC + ECAL_CORE_NAMESPACE_V5_INLINE=1 + ECAL_CORE_V5_FUNCTIONALTIY=1 +) + +### +## Iinstall header files only once... +## install(DIRECTORY "include/" DESTINATION "${INSTALL_INCLUDE_DIR}" COMPONENT sdk FILES_MATCHING PATTERN "*.h") @@ -685,12 +763,6 @@ install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include/" DESTINATION "${INSTALL_INCLUDE_DIR}" COMPONENT sdk FILES_MATCHING PATTERN "*.h") -if(NOT ${CMAKE_VERSION} VERSION_LESS "3.8.0") - source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES - ${ecal_sources} - ) -endif() - # eCAL process stub if(UNIX) set(PROJECT_NAME_PROCESS_STUB process_stub) diff --git a/ecal/core/include/ecal/ecal.h b/ecal/core/include/ecal/ecal.h index 8cd5bedaf9..04f87f6dc3 100644 --- a/ecal/core/include/ecal/ecal.h +++ b/ecal/core/include/ecal/ecal.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2024 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,19 +28,21 @@ #include #include #include -#include +#include #include #include #include #include #include -#include #include -#include -#include -#include +#include +#include #include #include #include #include #include +#include +#include +#include +#include \ No newline at end of file diff --git a/ecal/core/include/ecal/ecal_callback.h b/ecal/core/include/ecal/ecal_callback.h index 7e47475997..71ff242cdf 100644 --- a/ecal/core/include/ecal/ecal_callback.h +++ b/ecal/core/include/ecal/ecal_callback.h @@ -25,191 +25,12 @@ #pragma once #include -#include - #include -#include namespace eCAL { - /** - * @brief eCAL subscriber receive callback struct. - **/ - struct SReceiveCallbackData - { - void* buf = nullptr; //!< payload buffer - long size = 0; //!< payload buffer size - long long id = 0; //!< publisher id (SetId()) - long long time = 0; //!< publisher send time in µs - long long clock = 0; //!< publisher send clock - }; - - /** - * @brief eCAL subscriber event callback type. -**/ - enum class eSubscriberEvent - { - none = 0, - connected = 1, - disconnected = 2, - dropped = 3 - }; - - inline std::string to_string(eSubscriberEvent event_) { - switch (event_) { - case eSubscriberEvent::none: return "NONE"; - case eSubscriberEvent::connected: return "CONNECTED"; - case eSubscriberEvent::disconnected: return "DISCONNECTED"; - case eSubscriberEvent::dropped : return "DROPPED"; - default: return "Unknown"; - } - } - - /** - * @brief eCAL publisher event callback type. - **/ - enum class ePublisherEvent - { - none = 0, - connected = 1, - disconnected = 2, - dropped = 3 - }; - - inline std::string to_string(ePublisherEvent event_) { - switch (event_) { - case ePublisherEvent::none: return "NONE"; - case ePublisherEvent::connected: return "CONNECTED"; - case ePublisherEvent::disconnected: return "DISCONNECTED"; - case ePublisherEvent::dropped: return "DROPPED"; - default: return "Unknown"; - } - } - - /** - * @brief eCAL service client event callback type. - **/ - enum class eClientEvent - { - none = 0, - connected = 1, - disconnected = 2, - timeout = 3, - }; - - inline std::string to_string(eClientEvent event_) { - switch (event_) { - case eClientEvent::none: return "NONE"; - case eClientEvent::connected: return "CONNECTED"; - case eClientEvent::disconnected: return "DISCONNECTED"; - default: return "Unknown"; - } - } - - /** - * @brief eCAL service server event callback type. - **/ - enum class eServerEvent - { - none = 0, - connected = 1, - disconnected = 2, - }; - - inline std::string to_string(eServerEvent event_) { - switch (event_) { - case eServerEvent::none: return "NONE"; - case eServerEvent::connected: return "CONNECTED"; - case eServerEvent::disconnected: return "DISCONNECTED"; - default: return "Unknown"; - } - } - /** * @brief Timer callback function type. **/ using TimerCallbackT = std::function; - - inline namespace v6 - { - /** - * @brief Receive callback function type with topic id and data struct. The topic id contains the topic name, the process - * name, the host name and a uniques topic identifier. - * - * @param topic_id_ The topic id struct of the received message. - * @param data_type_info_ Topic data type information (encoding, type, descriptor). - * @param data_ Data struct containing payload, timestamp and publication clock. - **/ - using ReceiveCallbackT = std::function; - - /** - * @brief eCAL publisher event callback struct. - **/ - struct SPubEventCallbackData - { - ePublisherEvent event_type{ ePublisherEvent::none }; //!< publisher event type - long long event_time{ 0 }; //!< publisher event time in µs (eCAL time) - SDataTypeInformation subscriber_datatype; //!< datatype description of the connected subscriber - }; - - /** - * @brief Publisher event callback function type. - * - * @param topic_id_ The topic id struct of the received message. - * @param data_ Event callback data structure with the event specific information. - **/ - using PubEventCallbackT = std::function; - - /** - * @brief eCAL subscriber event callback struct. - **/ - struct SSubEventCallbackData - { - eSubscriberEvent event_type{ eSubscriberEvent::none }; //!< subscriber event type - long long event_time{ 0 }; //!< subscriber event time in µs (eCAL time) - SDataTypeInformation publisher_datatype; //!< topic information of the connected publisher - }; - - /** - * @brief Subscriber event callback function type. - * - * @param topic_id_ The topic id struct of the received message. - * @param data_ Event callback data structure with the event specific information. - **/ - using SubEventCallbackT = std::function; - - /** - * @brief eCAL client event callback struct. - **/ - struct SClientEventCallbackData - { - eClientEvent type{ eClientEvent::none }; //!< event type - long long time = 0; //!< event time in µs - }; - - /** - * @brief Client event callback function type. - * - * @param service_id_ The service id struct of the connection that triggered the event. - * @param data_ Event callback data structure with the event specific information. - **/ - using ClientEventCallbackT = std::function; - - /** - * @brief eCAL server event callback struct. - **/ - struct SServerEventCallbackData - { - eServerEvent type{ eServerEvent::none }; //!< event type - long long time = 0; //!< event time in µs - }; - - /** - * @brief Server event callback function type. - * - * @param service_id_ The service id struct of the connection that triggered the event. - * @param data_ Event callback data structure with the event specific information. - **/ - using ServerEventCallbackT = std::function; - } } diff --git a/ecal/core/include/ecal/ecal_namespace.h b/ecal/core/include/ecal/ecal_namespace.h new file mode 100644 index 0000000000..64132da3fa --- /dev/null +++ b/ecal/core/include/ecal/ecal_namespace.h @@ -0,0 +1,34 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2025 Continental Corporation + * + * 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. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @file ecal_namespace.h + * @brief eCAL namespace definitions (for switching between v5 / v6 namespaces +**/ + +#pragma once + +#if ECAL_CORE_NAMESPACE_V5_INLINE +#define ECAL_CORE_NAMESPACE_V5 inline namespace v5 +#define ECAL_CORE_NAMESPACE_V6 namespace v6 +#else +#define ECAL_CORE_NAMESPACE_V5 namespace v5 +#define ECAL_CORE_NAMESPACE_V6 inline namespace v6 +#endif + diff --git a/ecal/core/include/ecal/ecal_process.h b/ecal/core/include/ecal/ecal_process.h index b75fa5319d..7d9555213f 100644 --- a/ecal/core/include/ecal/ecal_process.h +++ b/ecal/core/include/ecal/ecal_process.h @@ -30,7 +30,6 @@ #include #include #include -#include namespace eCAL { diff --git a/ecal/core/include/ecal/ecal_registration.h b/ecal/core/include/ecal/ecal_registration.h index 2e87b6d8a1..fdacb3934b 100644 --- a/ecal/core/include/ecal/ecal_registration.h +++ b/ecal/core/include/ecal/ecal_registration.h @@ -25,7 +25,8 @@ #pragma once #include -#include +#include +#include #include #include diff --git a/ecal/core/include/ecal/ecal_types.h b/ecal/core/include/ecal/ecal_types.h index f985e611fa..b348c44dba 100644 --- a/ecal/core/include/ecal/ecal_types.h +++ b/ecal/core/include/ecal/ecal_types.h @@ -75,33 +75,6 @@ namespace eCAL //!< @endcond }; - /** - * @brief Optional compile time information associated with a given service method - * (necessary for reflection / runtime type checking) - **/ - struct SServiceMethodInformation - { - SDataTypeInformation request_type; //!< Data type description of the request - SDataTypeInformation response_type; //!< Data type description of the response - - //!< @cond - bool operator==(const SServiceMethodInformation& other) const - { - return request_type == other.request_type && response_type == other.response_type; - } - - bool operator!=(const SServiceMethodInformation& other) const - { - return !(*this == other); - } - - bool operator<(const SServiceMethodInformation& rhs) const - { - return std::tie(request_type, response_type) < std::tie(rhs.request_type, rhs.response_type); - } - //!< @endcond - }; - namespace Registration { using EntityIdT = uint64_t; @@ -130,61 +103,5 @@ namespace eCAL << ", host_name: " << id.host_name << ")"; return os; } - - struct STopicId - { - SEntityId topic_id; - std::string topic_name; - - bool operator==(const STopicId& other) const - { - return topic_id == other.topic_id && topic_name == other.topic_name; - } - - bool operator<(const STopicId& other) const - { - return std::tie(topic_id, topic_name) < std::tie(other.topic_id, other.topic_name); - } - }; - - inline std::ostream& operator<<(std::ostream& os, const STopicId& id) - { - os << "STopicId(topic_id: " << id.topic_id - << ", topic_name: " << id.topic_name << ")"; - return os; - } - - struct SServiceId - { - SEntityId service_id; - std::string service_name; - - bool operator==(const SServiceId& other) const - { - return service_id == other.service_id && service_name == other.service_name; - } - - bool operator<(const SServiceId& other) const - { - return std::tie(service_id, service_name) < std::tie(other.service_id, other.service_name); - } - }; - - struct SServiceMethodId - { - SEntityId service_id; - std::string service_name; - std::string method_name; - - bool operator==(const SServiceMethodId& other) const - { - return service_id == other.service_id && service_name == other.service_name && method_name == other.method_name; - } - - bool operator<(const SServiceMethodId& other) const - { - return std::tie(service_id, service_name, method_name) < std::tie(other.service_id, other.service_name, other.method_name); - } - }; } } diff --git a/ecal/core/include/ecal/msg/dynamic.h b/ecal/core/include/ecal/msg/dynamic.h index 3231e9f971..866a24b1fa 100644 --- a/ecal/core/include/ecal/msg/dynamic.h +++ b/ecal/core/include/ecal/msg/dynamic.h @@ -29,7 +29,7 @@ #include #include -#include +#include #include namespace eCAL diff --git a/ecal/core/include/ecal/msg/publisher.h b/ecal/core/include/ecal/msg/publisher.h index 900a9b57b0..7c72e5c418 100644 --- a/ecal/core/include/ecal/msg/publisher.h +++ b/ecal/core/include/ecal/msg/publisher.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2024 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,7 @@ #pragma once #include -#include +#include #include #include diff --git a/ecal/core/include/ecal/msg/subscriber.h b/ecal/core/include/ecal/msg/subscriber.h index 75cc78bce9..9e8c4bc989 100644 --- a/ecal/core/include/ecal/msg/subscriber.h +++ b/ecal/core/include/ecal/msg/subscriber.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2024 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,7 @@ #pragma once #include -#include +#include #include #include diff --git a/ecal/core/include/ecal/ecal_payload_writer.h b/ecal/core/include/ecal/pubsub/payload_writer.h similarity index 99% rename from ecal/core/include/ecal/ecal_payload_writer.h rename to ecal/core/include/ecal/pubsub/payload_writer.h index 6ea98a762c..df924cb8e8 100644 --- a/ecal/core/include/ecal/ecal_payload_writer.h +++ b/ecal/core/include/ecal/pubsub/payload_writer.h @@ -18,7 +18,7 @@ */ /** - * @file ecal_payload_writer.h + * @file payload_writer.h * @brief eCAL payload writer base class **/ diff --git a/ecal/core/include/ecal/ecal_publisher.h b/ecal/core/include/ecal/pubsub/publisher.h similarity index 97% rename from ecal/core/include/ecal/ecal_publisher.h rename to ecal/core/include/ecal/pubsub/publisher.h index 2e26b0b52e..13fc691a0b 100644 --- a/ecal/core/include/ecal/ecal_publisher.h +++ b/ecal/core/include/ecal/pubsub/publisher.h @@ -18,19 +18,20 @@ */ /** - * @file ecal_publisher.h + * @file publisher.h * @brief eCAL publisher interface **/ #pragma once #include +#include #include -#include +#include +#include + #include -#include -#include #include #include @@ -39,7 +40,7 @@ namespace eCAL { class CPublisherImpl; - inline namespace v6 + ECAL_CORE_NAMESPACE_V6 { /** * @brief eCAL publisher class. diff --git a/ecal/core/include/ecal/ecal_subscriber.h b/ecal/core/include/ecal/pubsub/subscriber.h similarity index 97% rename from ecal/core/include/ecal/ecal_subscriber.h rename to ecal/core/include/ecal/pubsub/subscriber.h index 5e2fb66751..8105c15f9d 100644 --- a/ecal/core/include/ecal/ecal_subscriber.h +++ b/ecal/core/include/ecal/pubsub/subscriber.h @@ -18,18 +18,18 @@ */ /** - * @file ecal_subscriber.h + * @file subscriber.h * @brief eCAL subscriber interface **/ #pragma once #include +#include #include -#include +#include #include -#include #include #include @@ -38,7 +38,7 @@ namespace eCAL { class CSubscriberImpl; - inline namespace v6 + ECAL_CORE_NAMESPACE_V6 { /** * @brief eCAL subscriber class. diff --git a/ecal/core/include/ecal/pubsub/types.h b/ecal/core/include/ecal/pubsub/types.h new file mode 100644 index 0000000000..b67b2e896b --- /dev/null +++ b/ecal/core/include/ecal/pubsub/types.h @@ -0,0 +1,164 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2025 Continental Corporation + * + * 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. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @file types.h + * @brief eCAL subscriber callback interface +**/ + +#pragma once + +#include +#include +#include + +#include +#include + +namespace eCAL +{ + namespace Registration + { + struct STopicId + { + SEntityId topic_id; + std::string topic_name; + + bool operator==(const STopicId& other) const + { + return topic_id == other.topic_id && topic_name == other.topic_name; + } + + bool operator<(const STopicId& other) const + { + return std::tie(topic_id, topic_name) < std::tie(other.topic_id, other.topic_name); + } + }; + + inline std::ostream& operator<<(std::ostream& os, const STopicId& id) + { + os << "STopicId(topic_id: " << id.topic_id + << ", topic_name: " << id.topic_name << ")"; + return os; + } + } + + /** + * @brief eCAL subscriber receive callback struct. + **/ + struct SReceiveCallbackData + { + void* buf = nullptr; //!< payload buffer + long size = 0; //!< payload buffer size + long long id = 0; //!< publisher id (SetId()) + long long time = 0; //!< publisher send time in µs + long long clock = 0; //!< publisher send clock + }; + + /** + * @brief eCAL subscriber event callback type. +**/ + enum class eSubscriberEvent + { + none = 0, + connected = 1, + disconnected = 2, + dropped = 3 + }; + + inline std::string to_string(eSubscriberEvent event_) { + switch (event_) { + case eSubscriberEvent::none: return "NONE"; + case eSubscriberEvent::connected: return "CONNECTED"; + case eSubscriberEvent::disconnected: return "DISCONNECTED"; + case eSubscriberEvent::dropped : return "DROPPED"; + default: return "Unknown"; + } + } + + /** + * @brief eCAL publisher event callback type. + **/ + enum class ePublisherEvent + { + none = 0, + connected = 1, + disconnected = 2, + dropped = 3 + }; + + inline std::string to_string(ePublisherEvent event_) { + switch (event_) { + case ePublisherEvent::none: return "NONE"; + case ePublisherEvent::connected: return "CONNECTED"; + case ePublisherEvent::disconnected: return "DISCONNECTED"; + case ePublisherEvent::dropped: return "DROPPED"; + default: return "Unknown"; + } + } + + ECAL_CORE_NAMESPACE_V6 + { + /** + * @brief Receive callback function type with topic id and data struct. The topic id contains the topic name, the process + * name, the host name and a uniques topic identifier. + * + * @param topic_id_ The topic id struct of the received message. + * @param data_type_info_ Topic data type information (encoding, type, descriptor). + * @param data_ Data struct containing payload, timestamp and publication clock. + **/ + using ReceiveCallbackT = std::function; + + /** + * @brief eCAL publisher event callback struct. + **/ + struct SPubEventCallbackData + { + ePublisherEvent event_type{ ePublisherEvent::none }; //!< publisher event type + long long event_time{ 0 }; //!< publisher event time in µs (eCAL time) + SDataTypeInformation subscriber_datatype; //!< datatype description of the connected subscriber + }; + + /** + * @brief Publisher event callback function type. + * + * @param topic_id_ The topic id struct of the received message. + * @param data_ Event callback data structure with the event specific information. + **/ + using PubEventCallbackT = std::function; + + /** + * @brief eCAL subscriber event callback struct. + **/ + struct SSubEventCallbackData + { + eSubscriberEvent event_type{ eSubscriberEvent::none }; //!< subscriber event type + long long event_time{ 0 }; //!< subscriber event time in µs (eCAL time) + SDataTypeInformation publisher_datatype; //!< topic information of the connected publisher + }; + + /** + * @brief Subscriber event callback function type. + * + * @param topic_id_ The topic id struct of the received message. + * @param data_ Event callback data structure with the event specific information. + **/ + using SubEventCallbackT = std::function; + } +} diff --git a/ecal/core/include/ecal/ecal_client.h b/ecal/core/include/ecal/service/client.h similarity index 95% rename from ecal/core/include/ecal/ecal_client.h rename to ecal/core/include/ecal/service/client.h index 2803de560c..1cb2396c6f 100644 --- a/ecal/core/include/ecal/ecal_client.h +++ b/ecal/core/include/ecal/service/client.h @@ -18,19 +18,18 @@ */ /** - * @file ecal_client.h + * @file client.h * @brief eCAL client interface **/ #pragma once #include +#include #include -#include -#include -#include -#include +#include +#include #include #include @@ -40,7 +39,7 @@ namespace eCAL { class CServiceClientImpl; - inline namespace v6 + ECAL_CORE_NAMESPACE_V6 { /** * @brief Service client wrapper class. @@ -157,7 +156,7 @@ namespace eCAL bool IsConnected() const; private: - std::shared_ptr m_service_client_impl; + std::shared_ptr m_service_client_impl; }; } } diff --git a/ecal/core/include/ecal/ecal_client_instance.h b/ecal/core/include/ecal/service/client_instance.h similarity index 89% rename from ecal/core/include/ecal/ecal_client_instance.h rename to ecal/core/include/ecal/service/client_instance.h index ecfc9b49ad..8f85e39d8c 100644 --- a/ecal/core/include/ecal/ecal_client_instance.h +++ b/ecal/core/include/ecal/service/client_instance.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2024 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,31 +18,34 @@ */ /** - * @file ecal_client_instance.h + * @file client_instance.h * @brief eCAL client instance interface **/ #pragma once -#include #include +#include #include -#include -#include + +#include #include #include namespace eCAL { - class CServiceClientImpl; + ECAL_CORE_NAMESPACE_V6 + { + class CServiceClientImpl; + } class ECAL_API_CLASS CClientInstance final { public: // Constructor ECAL_API_EXPORTED_MEMBER - CClientInstance(const Registration::SEntityId& entity_id_, const std::shared_ptr& service_client_id_impl_); + CClientInstance(const Registration::SEntityId& entity_id_, const std::shared_ptr& service_client_id_impl_); // Defaulted destructor ~CClientInstance() = default; @@ -109,7 +112,7 @@ namespace eCAL Registration::SEntityId GetClientID() const; private: - Registration::SEntityId m_entity_id; - const std::shared_ptr m_service_client_impl; + Registration::SEntityId m_entity_id; + const std::shared_ptr m_service_client_impl; }; } diff --git a/ecal/core/include/ecal/ecal_server.h b/ecal/core/include/ecal/service/server.h similarity index 95% rename from ecal/core/include/ecal/ecal_server.h rename to ecal/core/include/ecal/service/server.h index 7cda8bdf31..56661a6667 100644 --- a/ecal/core/include/ecal/ecal_server.h +++ b/ecal/core/include/ecal/service/server.h @@ -18,28 +18,27 @@ */ /** - * @file ecal_server.h + * @file server.h * @brief eCAL server interface **/ #pragma once #include +#include #include -#include -#include -#include +#include #include #include namespace eCAL { - class CServiceServerImpl; - - inline namespace v6 + ECAL_CORE_NAMESPACE_V6 { + class CServiceServerImpl; + /** * @brief Service Server wrapper class. **/ diff --git a/ecal/core/include/ecal/ecal_service_info.h b/ecal/core/include/ecal/service/types.h similarity index 54% rename from ecal/core/include/ecal/ecal_service_info.h rename to ecal/core/include/ecal/service/types.h index 9357c02d21..ff53a11273 100644 --- a/ecal/core/include/ecal/ecal_service_info.h +++ b/ecal/core/include/ecal/service/types.h @@ -18,12 +18,13 @@ */ /** - * @file ecal_service_info.h - * @brief eCAL service info + * @file types.h + * @brief Type definitions for eCAL services **/ #pragma once +#include #include #include @@ -44,6 +45,82 @@ namespace eCAL failed //!< failed }; + /** + * @brief eCAL service client event callback type. + **/ + enum class eClientEvent + { + none = 0, + connected = 1, + disconnected = 2, + timeout = 3, + }; + + inline std::string to_string(eClientEvent event_) { + switch (event_) { + case eClientEvent::none: return "NONE"; + case eClientEvent::connected: return "CONNECTED"; + case eClientEvent::disconnected: return "DISCONNECTED"; + default: return "Unknown"; + } + } + + /** + * @brief eCAL service server event callback type. + **/ + enum class eServerEvent + { + none = 0, + connected = 1, + disconnected = 2, + }; + + inline std::string to_string(eServerEvent event_) { + switch (event_) { + case eServerEvent::none: return "NONE"; + case eServerEvent::connected: return "CONNECTED"; + case eServerEvent::disconnected: return "DISCONNECTED"; + default: return "Unknown"; + } + } + + namespace Registration + { + + struct SServiceId + { + SEntityId service_id; + std::string service_name; + + bool operator==(const SServiceId& other) const + { + return service_id == other.service_id && service_name == other.service_name; + } + + bool operator<(const SServiceId& other) const + { + return std::tie(service_id, service_name) < std::tie(other.service_id, other.service_name); + } + }; + + struct SServiceMethodId + { + SEntityId service_id; + std::string service_name; + std::string method_name; + + bool operator==(const SServiceMethodId& other) const + { + return service_id == other.service_id && service_name == other.service_name && method_name == other.method_name; + } + + bool operator<(const SServiceMethodId& other) const + { + return std::tie(service_id, service_name, method_name) < std::tie(other.service_id, other.service_name, other.method_name); + } + }; + } + /** * @brief Service method information struct containing the request and response type information. **/ @@ -54,6 +131,33 @@ namespace eCAL SDataTypeInformation resp_type; //!< The type of the method response. }; + /** + * @brief Optional compile time information associated with a given service method + * (necessary for reflection / runtime type checking) + **/ + struct SServiceMethodInformation + { + SDataTypeInformation request_type; //!< Data type description of the request + SDataTypeInformation response_type; //!< Data type description of the response + + //!< @cond + bool operator==(const SServiceMethodInformation& other) const + { + return request_type == other.request_type && response_type == other.response_type; + } + + bool operator!=(const SServiceMethodInformation& other) const + { + return !(*this == other); + } + + bool operator<(const SServiceMethodInformation& rhs) const + { + return std::tie(request_type, response_type) < std::tie(rhs.request_type, rhs.response_type); + } + //!< @endcond + }; + /** * @brief Service response struct containing the (responding) server informations and the response itself. (deprecated) **/ @@ -127,4 +231,42 @@ namespace eCAL * @brief Map of . **/ using ServiceMethodInformationMapT = std::map; + + ECAL_CORE_NAMESPACE_V6 + { + /** + * @brief eCAL client event callback struct. + **/ + struct SClientEventCallbackData + { + eClientEvent type{ eClientEvent::none }; //!< event type + long long time = 0; //!< event time in µs + }; + + /** + * @brief Client event callback function type. + * + * @param service_id_ The service id struct of the connection that triggered the event. + * @param data_ Event callback data structure with the event specific information. + **/ + using ClientEventCallbackT = std::function; + + /** + * @brief eCAL server event callback struct. + **/ + struct SServerEventCallbackData + { + eServerEvent type{ eServerEvent::none }; //!< event type + long long time = 0; //!< event time in µs + }; + + /** + * @brief Server event callback function type. + * + * @param service_id_ The service id struct of the connection that triggered the event. + * @param data_ Event callback data structure with the event specific information. + **/ + using ServerEventCallbackT = std::function; + } + } diff --git a/ecal/core/include/ecal/ecal_callback_v5.h b/ecal/core/include/ecal/v5/ecal_callback.h similarity index 96% rename from ecal/core/include/ecal/ecal_callback_v5.h rename to ecal/core/include/ecal/v5/ecal_callback.h index 3c6d5254c6..24314331e8 100644 --- a/ecal/core/include/ecal/ecal_callback_v5.h +++ b/ecal/core/include/ecal/v5/ecal_callback.h @@ -24,16 +24,18 @@ #pragma once +#include + #include -#include -#include +#include // Should we instead bring back our old event types??? +#include // Should we instead bring back our old event types??? #include #include namespace eCAL { - namespace v5 + ECAL_CORE_NAMESPACE_V5 { /** * @brief eCAL publisher event callback struct. diff --git a/ecal/core/include/ecal/ecal_client_v5.h b/ecal/core/include/ecal/v5/ecal_client.h similarity index 97% rename from ecal/core/include/ecal/ecal_client_v5.h rename to ecal/core/include/ecal/v5/ecal_client.h index f8db9dbffb..75595dd187 100644 --- a/ecal/core/include/ecal/ecal_client_v5.h +++ b/ecal/core/include/ecal/v5/ecal_client.h @@ -18,23 +18,25 @@ */ /** - * @file ecal_client_v5.h + * @file ecal_client.h * @brief eCAL client interface (deprecated eCAL5 version) **/ #pragma once +#include + #include #include -#include -#include +#include +#include #include #include namespace eCAL { - namespace v5 + ECAL_CORE_NAMESPACE_V5 { class CServiceClientImpl; diff --git a/ecal/core/include/ecal/ecal_publisher_v5.h b/ecal/core/include/ecal/v5/ecal_publisher.h similarity index 98% rename from ecal/core/include/ecal/ecal_publisher_v5.h rename to ecal/core/include/ecal/v5/ecal_publisher.h index 97831df369..3c1c1097af 100644 --- a/ecal/core/include/ecal/ecal_publisher_v5.h +++ b/ecal/core/include/ecal/v5/ecal_publisher.h @@ -18,16 +18,18 @@ */ /** - * @file ecal_publisher_v5.h + * @file ecal_publisher.h * @brief eCAL publisher interface (deprecated eCAL5 version) **/ #pragma once -#include +#include + +#include #include #include -#include +#include #include #include #include @@ -41,7 +43,7 @@ namespace eCAL { class CPublisherImpl; - namespace v5 + ECAL_CORE_NAMESPACE_V5 { /** * @brief eCAL publisher class. diff --git a/ecal/core/include/ecal/ecal_server_v5.h b/ecal/core/include/ecal/v5/ecal_server.h similarity index 96% rename from ecal/core/include/ecal/ecal_server_v5.h rename to ecal/core/include/ecal/v5/ecal_server.h index 433e3f19c7..b496bd44b2 100644 --- a/ecal/core/include/ecal/ecal_server_v5.h +++ b/ecal/core/include/ecal/v5/ecal_server.h @@ -18,16 +18,18 @@ */ /** - * @file ecal_server_v5.h + * @file ecal_server.h * @brief eCAL server interface (deprecated eCAL5 version) **/ #pragma once +#include + #include #include -#include -#include +#include +#include #include #include @@ -35,7 +37,7 @@ namespace eCAL { - namespace v5 + ECAL_CORE_NAMESPACE_V5 { class CServiceServerImpl; diff --git a/ecal/core/include/ecal/ecal_subscriber_v5.h b/ecal/core/include/ecal/v5/ecal_subscriber.h similarity index 98% rename from ecal/core/include/ecal/ecal_subscriber_v5.h rename to ecal/core/include/ecal/v5/ecal_subscriber.h index 7b44bc3cae..680d535a5b 100644 --- a/ecal/core/include/ecal/ecal_subscriber_v5.h +++ b/ecal/core/include/ecal/v5/ecal_subscriber.h @@ -24,9 +24,11 @@ #pragma once +#include + #include #include -#include +#include #include #include #include @@ -40,7 +42,7 @@ namespace eCAL { class CSubscriberImpl; - namespace v5 + ECAL_CORE_NAMESPACE_V5 { /** * @brief eCAL subscriber class. diff --git a/ecal/core/src/ecal_descgate.h b/ecal/core/src/ecal_descgate.h index d5fbf5b03b..c59954dde9 100644 --- a/ecal/core/src/ecal_descgate.h +++ b/ecal/core/src/ecal_descgate.h @@ -24,7 +24,8 @@ #pragma once #include -#include +#include +#include #include #include "serialization/ecal_struct_sample_registration.h" diff --git a/ecal/core/src/io/shm/ecal_memfile.h b/ecal/core/src/io/shm/ecal_memfile.h index e569102209..e40e8e1745 100644 --- a/ecal/core/src/io/shm/ecal_memfile.h +++ b/ecal/core/src/io/shm/ecal_memfile.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,7 +28,7 @@ #include #include -#include +#include #include "ecal_memfile_info.h" #include "io/mtx/ecal_named_mutex.h" diff --git a/ecal/core/src/io/shm/ecal_memfile_sync.h b/ecal/core/src/io/shm/ecal_memfile_sync.h index 472e178827..6ac37f5a77 100644 --- a/ecal/core/src/io/shm/ecal_memfile_sync.h +++ b/ecal/core/src/io/shm/ecal_memfile_sync.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,7 @@ #include #include -#include +#include #include "readwrite/ecal_writer_data.h" #include "ecal_eventhandle.h" diff --git a/ecal/core/src/logging/ecal_log_provider.cpp b/ecal/core/src/logging/ecal_log_provider.cpp index 9b61c7683d..60f5571d10 100644 --- a/ecal/core/src/logging/ecal_log_provider.cpp +++ b/ecal/core/src/logging/ecal_log_provider.cpp @@ -51,18 +51,8 @@ namespace #include #include -namespace{ - bool isDirectory(const std::string& path_) - { - if (path_.empty()) return false; - - struct stat st; - if (stat(path_.c_str(), &st) == 0) - return S_ISDIR(st.st_mode); - - return false; - } - +namespace +{ std::string get_time_str() { char fmt[64]; @@ -149,9 +139,9 @@ namespace eCAL namespace Logging { CLogProvider::CLogProvider(const SProviderAttributes& attr_) - : m_attributes(attr_) - , m_created(false) + : m_created(false) , m_logfile(nullptr) + , m_attributes(attr_) { } diff --git a/ecal/core/src/logging/ecal_log_receiver.cpp b/ecal/core/src/logging/ecal_log_receiver.cpp index c25552af02..1db989e02d 100644 --- a/ecal/core/src/logging/ecal_log_receiver.cpp +++ b/ecal/core/src/logging/ecal_log_receiver.cpp @@ -37,8 +37,8 @@ namespace eCAL namespace Logging { CLogReceiver::CLogReceiver(const SReceiverAttributes& attr_) - : m_attributes(attr_) - , m_created(false) + : m_created(false) + , m_attributes(attr_) { } diff --git a/ecal/core/src/pubsub/ecal_publisher.cpp b/ecal/core/src/pubsub/ecal_publisher.cpp index bff91d95a8..a65e4fec57 100644 --- a/ecal/core/src/pubsub/ecal_publisher.cpp +++ b/ecal/core/src/pubsub/ecal_publisher.cpp @@ -38,98 +38,101 @@ namespace eCAL { - CPublisher::CPublisher(const std::string& topic_name_, const SDataTypeInformation& data_type_info_, const Publisher::Configuration& config_) + ECAL_CORE_NAMESPACE_V6 { - // create publisher implementation - m_publisher_impl = std::make_shared(data_type_info_, BuildWriterAttributes(topic_name_, config_, GetTransportLayerConfiguration(), GetRegistrationConfiguration())); - - // register publisher - if(g_pubgate() != nullptr) g_pubgate()->Register(topic_name_, m_publisher_impl); - } - - CPublisher::CPublisher(const std::string& topic_name_, const SDataTypeInformation& data_type_info_, const PubEventCallbackT event_callback_, const Publisher::Configuration& config_) : - CPublisher(topic_name_, data_type_info_, config_) - { - // add event callback for all current event types - m_publisher_impl->SetEventCallback(event_callback_); - } - - CPublisher::~CPublisher() - { - // could be already destroyed by move - if (m_publisher_impl == nullptr) return; - - // unregister publisher - if (g_pubgate() != nullptr) g_pubgate()->Unregister(m_publisher_impl->GetTopicName(), m_publisher_impl); - } - - CPublisher::CPublisher(CPublisher&& rhs) noexcept : - m_publisher_impl(std::move(rhs.m_publisher_impl)) - { - } - - CPublisher& CPublisher::operator=(CPublisher&& rhs) noexcept - { - if (this != &rhs) + CPublisher::CPublisher(const std::string & topic_name_, const SDataTypeInformation & data_type_info_, const Publisher::Configuration & config_) { - m_publisher_impl = std::move(rhs.m_publisher_impl); + // create publisher implementation + m_publisher_impl = std::make_shared(data_type_info_, BuildWriterAttributes(topic_name_, config_, GetTransportLayerConfiguration(), GetRegistrationConfiguration())); + + // register publisher + if (g_pubgate() != nullptr) g_pubgate()->Register(topic_name_, m_publisher_impl); } - return *this; - } - - bool CPublisher::Send(const void* const buf_, const size_t len_, const long long time_ /* = DEFAULT_TIME_ARGUMENT */) - { - CBufferPayloadWriter payload{ buf_, len_ }; - return Send(payload, time_); - } - bool CPublisher::Send(CPayloadWriter& payload_, long long time_) - { - if (m_publisher_impl == nullptr) return false; - - // in an optimization case the - // publisher can send an empty package - // or we do not have any subscription at all - // then the data writer will only do some statistics - // for the monitoring layer and return - if (GetSubscriberCount() == 0) - { - m_publisher_impl->RefreshSendCounter(); - // we return false here to indicate that we did not really send something - return false; - } - - // send content via data writer layer - const long long write_time = (time_ == DEFAULT_TIME_ARGUMENT) ? eCAL::Time::GetMicroSeconds() : time_; - return m_publisher_impl->Write(payload_, write_time, 0); - } - - bool CPublisher::Send(const std::string& payload_, long long time_) - { - return(Send(payload_.data(), payload_.size(), time_)); - } - - size_t CPublisher::GetSubscriberCount() const - { - if (m_publisher_impl == nullptr) return 0; - return(m_publisher_impl->GetSubscriberCount()); - } - - std::string CPublisher::GetTopicName() const - { - if (m_publisher_impl == nullptr) return ""; - return(m_publisher_impl->GetTopicName()); - } - - Registration::STopicId CPublisher::GetTopicId() const - { - if (m_publisher_impl == nullptr) return Registration::STopicId(); - return(m_publisher_impl->GetTopicId()); - } - - SDataTypeInformation CPublisher::GetDataTypeInformation() const - { - if (m_publisher_impl == nullptr) return SDataTypeInformation(); - return(m_publisher_impl->GetDataTypeInformation()); + CPublisher::CPublisher(const std::string & topic_name_, const SDataTypeInformation & data_type_info_, const PubEventCallbackT event_callback_, const Publisher::Configuration & config_) : + CPublisher(topic_name_, data_type_info_, config_) + { + // add event callback for all current event types + m_publisher_impl->SetEventCallback(event_callback_); + } + + CPublisher::~CPublisher() + { + // could be already destroyed by move + if (m_publisher_impl == nullptr) return; + + // unregister publisher + if (g_pubgate() != nullptr) g_pubgate()->Unregister(m_publisher_impl->GetTopicName(), m_publisher_impl); + } + + CPublisher::CPublisher(CPublisher && rhs) noexcept : + m_publisher_impl(std::move(rhs.m_publisher_impl)) + { + } + + CPublisher & CPublisher::operator=(CPublisher && rhs) noexcept + { + if (this != &rhs) + { + m_publisher_impl = std::move(rhs.m_publisher_impl); + } + return *this; + } + + bool CPublisher::Send(const void* const buf_, const size_t len_, const long long time_ /* = DEFAULT_TIME_ARGUMENT */) + { + CBufferPayloadWriter payload{ buf_, len_ }; + return Send(payload, time_); + } + + bool CPublisher::Send(CPayloadWriter & payload_, long long time_) + { + if (m_publisher_impl == nullptr) return false; + + // in an optimization case the + // publisher can send an empty package + // or we do not have any subscription at all + // then the data writer will only do some statistics + // for the monitoring layer and return + if (GetSubscriberCount() == 0) + { + m_publisher_impl->RefreshSendCounter(); + // we return false here to indicate that we did not really send something + return false; + } + + // send content via data writer layer + const long long write_time = (time_ == DEFAULT_TIME_ARGUMENT) ? eCAL::Time::GetMicroSeconds() : time_; + return m_publisher_impl->Write(payload_, write_time, 0); + } + + bool CPublisher::Send(const std::string & payload_, long long time_) + { + return(Send(payload_.data(), payload_.size(), time_)); + } + + size_t CPublisher::GetSubscriberCount() const + { + if (m_publisher_impl == nullptr) return 0; + return(m_publisher_impl->GetSubscriberCount()); + } + + std::string CPublisher::GetTopicName() const + { + if (m_publisher_impl == nullptr) return ""; + return(m_publisher_impl->GetTopicName()); + } + + Registration::STopicId CPublisher::GetTopicId() const + { + if (m_publisher_impl == nullptr) return Registration::STopicId(); + return(m_publisher_impl->GetTopicId()); + } + + SDataTypeInformation CPublisher::GetDataTypeInformation() const + { + if (m_publisher_impl == nullptr) return SDataTypeInformation(); + return(m_publisher_impl->GetDataTypeInformation()); + } } } diff --git a/ecal/core/src/pubsub/ecal_publisher_impl.cpp b/ecal/core/src/pubsub/ecal_publisher_impl.cpp index 47a790817c..a984ccd9d6 100644 --- a/ecal/core/src/pubsub/ecal_publisher_impl.cpp +++ b/ecal/core/src/pubsub/ecal_publisher_impl.cpp @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include @@ -401,7 +401,7 @@ namespace eCAL return(true); } - bool CPublisherImpl::SetEventCallback(const PubEventCallbackT callback_) + bool CPublisherImpl::SetEventCallback(const v6::PubEventCallbackT callback_) { if (!m_created) return false; @@ -728,7 +728,7 @@ namespace eCAL // new event handling with topic id if(m_event_id_callback) { - SPubEventCallbackData data; + v6::SPubEventCallbackData data; data.event_type = type_; data.event_time = eCAL::Time::GetMicroSeconds(); data.subscriber_datatype = data_type_info_; diff --git a/ecal/core/src/pubsub/ecal_publisher_impl.h b/ecal/core/src/pubsub/ecal_publisher_impl.h index 984b767d9d..8d3c18edaf 100644 --- a/ecal/core/src/pubsub/ecal_publisher_impl.h +++ b/ecal/core/src/pubsub/ecal_publisher_impl.h @@ -23,11 +23,10 @@ #pragma once -#include -#include -#include +#include +#include #include -#include +#include #include "serialization/ecal_serialize_sample_registration.h" #include "util/frequency_calculator.h" @@ -87,7 +86,7 @@ namespace eCAL bool RemoveEventCallback(ePublisherEvent type_); // future event callback interface - bool SetEventCallback(const PubEventCallbackT callback_); + bool SetEventCallback(const v6::PubEventCallbackT callback_); bool RemoveEventCallback(); bool SetAttribute(const std::string& attr_name_, const std::string& attr_value_); @@ -167,7 +166,7 @@ namespace eCAL EventCallbackMapT m_event_callback_map; std::mutex m_event_id_callback_mutex; - PubEventCallbackT m_event_id_callback; + v6::PubEventCallbackT m_event_id_callback; long long m_id = 0; long long m_clock = 0; diff --git a/ecal/core/src/pubsub/ecal_subscriber.cpp b/ecal/core/src/pubsub/ecal_subscriber.cpp index a48c76e3e6..82cc4f8473 100644 --- a/ecal/core/src/pubsub/ecal_subscriber.cpp +++ b/ecal/core/src/pubsub/ecal_subscriber.cpp @@ -31,78 +31,81 @@ namespace eCAL { - CSubscriber::CSubscriber(const std::string& topic_name_, const SDataTypeInformation& data_type_info_, const Subscriber::Configuration& config_) + ECAL_CORE_NAMESPACE_V6 { - // create subscriber implementation - m_subscriber_impl = std::make_shared(data_type_info_, BuildReaderAttributes(topic_name_, config_, GetTransportLayerConfiguration(), GetRegistrationConfiguration())); - - // register subscriber - if (g_subgate() != nullptr) g_subgate()->Register(topic_name_, m_subscriber_impl); - } - - CSubscriber::CSubscriber(const std::string& topic_name_, const SDataTypeInformation& data_type_info_, const SubEventCallbackT event_callback_, const Subscriber::Configuration& config_) : - CSubscriber(topic_name_, data_type_info_, config_) - { - // add event callback for all current event types - m_subscriber_impl->SetEventIDCallback(event_callback_); - } - - CSubscriber::~CSubscriber() - { - // could be already destroyed by move - if (m_subscriber_impl == nullptr) return; - - // unregister subscriber - if (g_subgate() != nullptr) g_subgate()->Unregister(m_subscriber_impl->GetTopicName(), m_subscriber_impl); - } - - CSubscriber::CSubscriber(CSubscriber&& rhs) noexcept : - m_subscriber_impl(std::move(rhs.m_subscriber_impl)) - { - } - - CSubscriber& CSubscriber::operator=(CSubscriber&& rhs) noexcept - { - if (this != &rhs) + CSubscriber::CSubscriber(const std::string & topic_name_, const SDataTypeInformation & data_type_info_, const Subscriber::Configuration & config_) { - m_subscriber_impl = std::move(rhs.m_subscriber_impl); + // create subscriber implementation + m_subscriber_impl = std::make_shared(data_type_info_, BuildReaderAttributes(topic_name_, config_, GetTransportLayerConfiguration(), GetRegistrationConfiguration())); + + // register subscriber + if (g_subgate() != nullptr) g_subgate()->Register(topic_name_, m_subscriber_impl); + } + + CSubscriber::CSubscriber(const std::string & topic_name_, const SDataTypeInformation & data_type_info_, const SubEventCallbackT event_callback_, const Subscriber::Configuration & config_) : + CSubscriber(topic_name_, data_type_info_, config_) + { + // add event callback for all current event types + m_subscriber_impl->SetEventIDCallback(event_callback_); + } + + CSubscriber::~CSubscriber() + { + // could be already destroyed by move + if (m_subscriber_impl == nullptr) return; + + // unregister subscriber + if (g_subgate() != nullptr) g_subgate()->Unregister(m_subscriber_impl->GetTopicName(), m_subscriber_impl); + } + + CSubscriber::CSubscriber(CSubscriber && rhs) noexcept : + m_subscriber_impl(std::move(rhs.m_subscriber_impl)) + { + } + + CSubscriber & CSubscriber::operator=(CSubscriber && rhs) noexcept + { + if (this != &rhs) + { + m_subscriber_impl = std::move(rhs.m_subscriber_impl); + } + return *this; + } + + bool CSubscriber::SetReceiveCallback(ReceiveCallbackT callback_) + { + if (m_subscriber_impl == nullptr) return false; + return m_subscriber_impl->SetReceiveCallback(std::move(callback_)); + } + + bool CSubscriber::RemoveReceiveCallback() + { + if (m_subscriber_impl == nullptr) return false; + return m_subscriber_impl->RemoveReceiveCallback(); + } + + size_t CSubscriber::GetPublisherCount() const + { + if (m_subscriber_impl == nullptr) return 0; + return m_subscriber_impl->GetPublisherCount(); + } + + std::string CSubscriber::GetTopicName() const + { + if (m_subscriber_impl == nullptr) return ""; + return m_subscriber_impl->GetTopicName(); + } + + Registration::STopicId CSubscriber::GetTopicId() const + { + if (m_subscriber_impl == nullptr) return{}; + return m_subscriber_impl->GetId(); + } + + SDataTypeInformation CSubscriber::GetDataTypeInformation() const + { + if (m_subscriber_impl == nullptr) return SDataTypeInformation{}; + return m_subscriber_impl->GetDataTypeInformation(); } - return *this; - } - - bool CSubscriber::SetReceiveCallback(ReceiveCallbackT callback_) - { - if (m_subscriber_impl == nullptr) return false; - return m_subscriber_impl->SetReceiveCallback(std::move(callback_)); - } - - bool CSubscriber::RemoveReceiveCallback() - { - if (m_subscriber_impl == nullptr) return false; - return m_subscriber_impl->RemoveReceiveCallback(); - } - - size_t CSubscriber::GetPublisherCount() const - { - if (m_subscriber_impl == nullptr) return 0; - return m_subscriber_impl->GetPublisherCount(); - } - - std::string CSubscriber::GetTopicName() const - { - if (m_subscriber_impl == nullptr) return ""; - return m_subscriber_impl->GetTopicName(); - } - - Registration::STopicId CSubscriber::GetTopicId() const - { - if (m_subscriber_impl == nullptr) return{}; - return m_subscriber_impl->GetId(); - } - - SDataTypeInformation CSubscriber::GetDataTypeInformation() const - { - if (m_subscriber_impl == nullptr) return SDataTypeInformation{}; - return m_subscriber_impl->GetDataTypeInformation(); } } diff --git a/ecal/core/src/pubsub/ecal_subscriber_impl.cpp b/ecal/core/src/pubsub/ecal_subscriber_impl.cpp index f5fbea7d37..4648aa90e3 100644 --- a/ecal/core/src/pubsub/ecal_subscriber_impl.cpp +++ b/ecal/core/src/pubsub/ecal_subscriber_impl.cpp @@ -21,6 +21,7 @@ * @brief common eCAL data reader **/ +#include "ecal_subscriber_impl.h" #include #include #include @@ -70,11 +71,11 @@ namespace eCAL CSubscriberImpl::CSubscriberImpl(const SDataTypeInformation& topic_info_, const eCAL::eCALReader::SAttributes& attr_) : m_topic_info(topic_info_), m_topic_size(0), - m_attributes(attr_), m_receive_time(0), m_clock(0), m_frequency_calculator(3.0f), - m_created(false) + m_created(false), + m_attributes(attr_) { #ifndef NDEBUG // log it @@ -164,7 +165,7 @@ namespace eCAL return(false); } - bool CSubscriberImpl::SetReceiveCallback(ReceiveCallbackT callback_) + bool CSubscriberImpl::SetReceiveCallback(v6::ReceiveCallbackT callback_) { if (!m_created) return(false); @@ -232,7 +233,7 @@ namespace eCAL return(true); } - bool CSubscriberImpl::SetEventIDCallback(const SubEventCallbackT callback_) + bool CSubscriberImpl::SetEventIDCallback(const v6::SubEventCallbackT callback_) { if (!m_created) return false; @@ -781,7 +782,7 @@ namespace eCAL // new event handling with topic id if (m_event_id_callback) { - SSubEventCallbackData data; + v6::SSubEventCallbackData data; data.event_type = type_; data.event_time = eCAL::Time::GetMicroSeconds(); data.publisher_datatype = data_type_info_; diff --git a/ecal/core/src/pubsub/ecal_subscriber_impl.h b/ecal/core/src/pubsub/ecal_subscriber_impl.h index af6d375761..93092e7ef6 100644 --- a/ecal/core/src/pubsub/ecal_subscriber_impl.h +++ b/ecal/core/src/pubsub/ecal_subscriber_impl.h @@ -23,9 +23,8 @@ #pragma once -#include -#include -#include +#include +#include #include "serialization/ecal_serialize_sample_payload.h" #include "serialization/ecal_serialize_sample_registration.h" @@ -70,7 +69,7 @@ namespace eCAL bool Read(std::string& buf_, long long* time_ = nullptr, int rcv_timeout_ms_ = 0); - bool SetReceiveCallback(ReceiveCallbackT callback_); + bool SetReceiveCallback(v6::ReceiveCallbackT callback_); bool RemoveReceiveCallback(); // deprecated event callback interface @@ -78,7 +77,7 @@ namespace eCAL bool RemoveEventCallback(eSubscriberEvent type_); // future event callback interface - bool SetEventIDCallback(const SubEventCallbackT callback_); + bool SetEventIDCallback(const v6::SubEventCallbackT callback_); bool RemoveEventCallback(); bool SetAttribute(const std::string& attr_name_, const std::string& attr_value_); @@ -158,7 +157,7 @@ namespace eCAL long long m_read_time = 0; std::mutex m_receive_callback_mutex; - ReceiveCallbackT m_receive_callback; + v6::ReceiveCallbackT m_receive_callback; std::atomic m_receive_time; std::deque m_sample_hash_queue; @@ -168,7 +167,7 @@ namespace eCAL EventCallbackMapT m_event_callback_map; std::mutex m_event_id_callback_mutex; - SubEventCallbackT m_event_id_callback; + v6::SubEventCallbackT m_event_id_callback; std::atomic m_clock; diff --git a/ecal/core/src/readwrite/ecal_writer_base.h b/ecal/core/src/readwrite/ecal_writer_base.h index 641d31fc7d..e7d0669542 100644 --- a/ecal/core/src/readwrite/ecal_writer_base.h +++ b/ecal/core/src/readwrite/ecal_writer_base.h @@ -23,7 +23,7 @@ #pragma once -#include +#include #include "ecal_writer_data.h" #include "ecal_writer_info.h" diff --git a/ecal/core/src/readwrite/ecal_writer_buffer_payload.h b/ecal/core/src/readwrite/ecal_writer_buffer_payload.h index 5a1c49caf6..cb8bad57a3 100644 --- a/ecal/core/src/readwrite/ecal_writer_buffer_payload.h +++ b/ecal/core/src/readwrite/ecal_writer_buffer_payload.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ #pragma once -#include +#include #include diff --git a/ecal/core/src/service/ecal_clientgate.cpp b/ecal/core/src/service/ecal_clientgate.cpp index e7ed994b45..60b2b09f58 100644 --- a/ecal/core/src/service/ecal_clientgate.cpp +++ b/ecal/core/src/service/ecal_clientgate.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2024 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -60,18 +60,18 @@ namespace eCAL m_created = false; } - bool CClientGate::Register(const std::string& service_name_, const std::shared_ptr& client_) + bool CClientGate::Register(const std::string& service_name_, const std::shared_ptr& client_) { if (!m_created) return(false); // register internal client const std::unique_lock lock(m_service_client_map_mutex); - m_service_client_map.emplace(std::pair>(service_name_, client_)); + m_service_client_map.emplace(std::pair>(service_name_, client_)); return(true); } - bool CClientGate::Unregister(const std::string& service_name_, const std::shared_ptr& client_) + bool CClientGate::Unregister(const std::string& service_name_, const std::shared_ptr& client_) { if (!m_created) return(false); bool ret_state = false; diff --git a/ecal/core/src/service/ecal_clientgate.h b/ecal/core/src/service/ecal_clientgate.h index b4568b4842..39a653429d 100644 --- a/ecal/core/src/service/ecal_clientgate.h +++ b/ecal/core/src/service/ecal_clientgate.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2024 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ #pragma once +#include #include "ecal_def.h" #include "serialization/ecal_struct_sample_registration.h" @@ -36,7 +37,10 @@ namespace eCAL { - class CServiceClientImpl; + ECAL_CORE_NAMESPACE_V6 + { + class CServiceClientImpl; + } class CClientGate { @@ -47,8 +51,8 @@ namespace eCAL void Start(); void Stop(); - bool Register (const std::string& service_name_, const std::shared_ptr& client_); - bool Unregister(const std::string& service_name_, const std::shared_ptr& client_); + bool Register (const std::string& service_name_, const std::shared_ptr& client_); + bool Unregister(const std::string& service_name_, const std::shared_ptr& client_); void ApplyServiceRegistration(const Registration::Sample& ecal_sample_); @@ -57,7 +61,7 @@ namespace eCAL protected: static std::atomic m_created; - using ServiceNameClientIDImplMapT = std::multimap>; + using ServiceNameClientIDImplMapT = std::multimap>; std::shared_timed_mutex m_service_client_map_mutex; ServiceNameClientIDImplMapT m_service_client_map; }; diff --git a/ecal/core/src/service/ecal_service_client.cpp b/ecal/core/src/service/ecal_service_client.cpp index b8c56a2f12..060239ca33 100644 --- a/ecal/core/src/service/ecal_service_client.cpp +++ b/ecal/core/src/service/ecal_service_client.cpp @@ -21,6 +21,7 @@ * @brief eCAL service client interface **/ +#include #include #include "ecal_clientgate.h" @@ -31,7 +32,9 @@ namespace eCAL { - CServiceClient::CServiceClient(const std::string& service_name_, const ServiceMethodInformationMapT method_information_map_, const ClientEventCallbackT event_callback_) + ECAL_CORE_NAMESPACE_V6 + { + CServiceClient::CServiceClient(const std::string & service_name_, const ServiceMethodInformationMapT method_information_map_, const ClientEventCallbackT event_callback_) { // create client implementation m_service_client_impl = CServiceClientImpl::CreateInstance(service_name_, method_information_map_, event_callback_); @@ -49,12 +52,12 @@ namespace eCAL if (g_clientgate() != nullptr) g_clientgate()->Unregister(m_service_client_impl->GetServiceName(), m_service_client_impl); } - CServiceClient::CServiceClient(CServiceClient&& rhs) noexcept + CServiceClient::CServiceClient(CServiceClient && rhs) noexcept : m_service_client_impl(std::move(rhs.m_service_client_impl)) { } - CServiceClient& CServiceClient::operator=(CServiceClient&& rhs) noexcept + CServiceClient & CServiceClient::operator=(CServiceClient && rhs) noexcept { if (this != &rhs) { @@ -77,7 +80,7 @@ namespace eCAL return instances; } - bool CServiceClient::CallWithResponse(const std::string& method_name_, const std::string& request_, int timeout_, ServiceIDResponseVecT& service_response_vec_) const + bool CServiceClient::CallWithResponse(const std::string & method_name_, const std::string & request_, int timeout_, ServiceIDResponseVecT & service_response_vec_) const { auto instances = GetClientInstances(); size_t num_instances = instances.size(); @@ -129,10 +132,10 @@ namespace eCAL } } - return overall_success; + return overall_success; } - bool CServiceClient::CallWithCallback(const std::string& method_name_, const std::string& request_, int timeout_, const ResponseIDCallbackT& response_callback_) const + bool CServiceClient::CallWithCallback(const std::string & method_name_, const std::string & request_, int timeout_, const ResponseIDCallbackT & response_callback_) const { auto instances = GetClientInstances(); size_t num_instances = instances.size(); @@ -167,7 +170,7 @@ namespace eCAL return return_state; } - bool CServiceClient::CallWithCallbackAsync(const std::string& method_name_, const std::string& request_, const ResponseIDCallbackT& response_callback_) const + bool CServiceClient::CallWithCallbackAsync(const std::string & method_name_, const std::string & request_, const ResponseIDCallbackT & response_callback_) const { bool return_state = true; auto instances = GetClientInstances(); @@ -199,4 +202,5 @@ namespace eCAL } return false; } + } } diff --git a/ecal/core/src/service/ecal_service_client_impl.cpp b/ecal/core/src/service/ecal_service_client_impl.cpp index 6e2ac382f3..8dfe122f6e 100644 --- a/ecal/core/src/service/ecal_service_client_impl.cpp +++ b/ecal/core/src/service/ecal_service_client_impl.cpp @@ -72,19 +72,21 @@ namespace namespace eCAL { - // Factory method to create a new instance of CServiceClientImpl - std::shared_ptr CServiceClientImpl::CreateInstance( - const std::string& service_name_, const ServiceMethodInformationMapT& method_information_map_, const ClientEventCallbackT& event_callback_) + ECAL_CORE_NAMESPACE_V6 { -#ifndef NDEBUG - eCAL::Logging::Log(eCAL::Logging::log_level_debug2, "CServiceClientImpl::CreateInstance: Creating instance of CServiceClientImpl for service: " + service_name_); -#endif - return std::shared_ptr(new CServiceClientImpl(service_name_, method_information_map_, event_callback_)); - } + // Factory method to create a new instance of CServiceClientImpl + std::shared_ptr CServiceClientImpl::CreateInstance( + const std::string & service_name_, const ServiceMethodInformationMapT & method_information_map_, const ClientEventCallbackT & event_callback_) + { + #ifndef NDEBUG + eCAL::Logging::Log(eCAL::Logging::log_level_debug2, "CServiceClientImpl::CreateInstance: Creating instance of CServiceClientImpl for service: " + service_name_); + #endif + return std::shared_ptr(new CServiceClientImpl(service_name_, method_information_map_, event_callback_)); + } // Constructor: Initializes client ID, method call counts, and registers the client CServiceClientImpl::CServiceClientImpl( - const std::string& service_name_, const ServiceMethodInformationMapT& method_information_map_, const ClientEventCallbackT& event_callback_) + const std::string & service_name_, const ServiceMethodInformationMapT & method_information_map_, const ClientEventCallbackT & event_callback_) : m_service_name(service_name_), m_method_information_map(method_information_map_) { #ifndef NDEBUG @@ -163,8 +165,8 @@ namespace eCAL // Calls a service method synchronously, blocking until a response is received or timeout occurs std::pair CServiceClientImpl::CallWithCallback( - const Registration::SEntityId& entity_id_, const std::string& method_name_, - const std::string& request_, int timeout_ms_, const ResponseIDCallbackT& response_callback_) + const Registration::SEntityId & entity_id_, const std::string & method_name_, + const std::string & request_, int timeout_ms_, const ResponseIDCallbackT & response_callback_) { #ifndef NDEBUG eCAL::Logging::Log(eCAL::Logging::log_level_debug1, "CServiceClientImpl::CallWithCallback: Performing synchronous call for service: " + m_service_name + ", method: " + method_name_); @@ -190,7 +192,7 @@ namespace eCAL { Registration::SServiceId service_id; service_id.service_name = m_service_name; - service_id.service_id = entity_id_; + service_id.service_id = entity_id_; NotifyEventCallback(service_id, eClientEvent::timeout); #ifndef NDEBUG eCAL::Logging::Log(eCAL::Logging::log_level_debug1, "CServiceClientImpl::CallWithCallback: Synchronous call for service: " + m_service_name + ", method: " + method_name_ + " timed out."); @@ -201,7 +203,7 @@ namespace eCAL } // Asynchronous call to a service with a specified timeout - bool CServiceClientImpl::CallWithCallbackAsync(const Registration::SEntityId& entity_id_, const std::string& method_name_, const std::string& request_, const ResponseIDCallbackT& response_callback_) + bool CServiceClientImpl::CallWithCallbackAsync(const Registration::SEntityId & entity_id_, const std::string & method_name_, const std::string & request_, const ResponseIDCallbackT & response_callback_) { #ifndef NDEBUG eCAL::Logging::Log(eCAL::Logging::log_level_debug2, "CServiceClientImpl::CallWithCallbackAsync: Performing asynchronous call for service: " + m_service_name + ", method: " + method_name_); @@ -234,7 +236,7 @@ namespace eCAL auto response_data = PrepareInitialResponse(client, method_name_); // Create the response callback - auto response = [client, response_data, entity_id_, response_callback_](const eCAL::service::Error& error, const std::shared_ptr& response_) + auto response = [client, response_data, entity_id_, response_callback_](const ecal_service::Error& error, const std::shared_ptr& response_) { const std::lock_guard lock(*response_data->mutex); if (!*response_data->block_modifying_response) @@ -275,7 +277,7 @@ namespace eCAL } // Check if a specific service is connected - bool CServiceClientImpl::IsConnected(const Registration::SEntityId& entity_id_) + bool CServiceClientImpl::IsConnected(const Registration::SEntityId & entity_id_) { const std::lock_guard lock(m_client_session_map_mutex); auto iter = m_client_session_map.find(entity_id_); @@ -286,7 +288,7 @@ namespace eCAL return state; } - void CServiceClientImpl::RegisterService(const Registration::SEntityId& entity_id_, const v5::SServiceAttr& service_) + void CServiceClientImpl::RegisterService(const Registration::SEntityId & entity_id_, const v5::SServiceAttr & service_) { const std::lock_guard lock(m_client_session_map_mutex); @@ -298,10 +300,10 @@ namespace eCAL if (client_manager == nullptr || client_manager->is_stopped()) return; // Event callback (unused) - const eCAL::service::ClientSession::EventCallbackT event_callback = [](eCAL::service::ClientEventType /*event*/, const std::string& /*message*/) -> void + const ecal_service::ClientSession::EventCallbackT event_callback = [](ecal_service::ClientEventType /*event*/, const std::string& /*message*/) -> void { - // TODO: Replace current connect/disconnect state logic with this client event callback logic - }; + // TODO: Replace current connect/disconnect state logic with this client event callback logic + }; // use protocol version 1 const auto protocol_version = 1; @@ -335,10 +337,10 @@ namespace eCAL { Registration::SServiceId service_id; - service_id.service_id.entity_id = m_client_id; + service_id.service_id.entity_id = m_client_id; service_id.service_id.process_id = Process::GetProcessID(); - service_id.service_id.host_name = Process::GetHostName(); - service_id.service_name = m_service_name; + service_id.service_id.host_name = Process::GetHostName(); + service_id.service_name = m_service_name; return service_id; } @@ -354,15 +356,15 @@ namespace eCAL ecal_reg_sample.cmd_type = bct_reg_client; auto& service_identifier = ecal_reg_sample.identifier; - service_identifier.entity_id = m_client_id; + service_identifier.entity_id = m_client_id; service_identifier.process_id = Process::GetProcessID(); - service_identifier.host_name = Process::GetHostName(); + service_identifier.host_name = Process::GetHostName(); auto& service_client = ecal_reg_sample.client; service_client.version = m_client_version; - service_client.pname = Process::GetProcessName(); - service_client.uname = Process::GetUnitName(); - service_client.sname = m_service_name; + service_client.pname = Process::GetProcessName(); + service_client.uname = Process::GetUnitName(); + service_client.sname = m_service_name; const std::lock_guard lock(m_method_information_map_mutex); for (const auto& method_information_pair : m_method_information_map) @@ -374,13 +376,13 @@ namespace eCAL method.mname = method_name; // old type and descriptor fields - method.req_type = method_information.request_type.name; - method.req_desc = method_information.request_type.descriptor; - method.resp_type = method_information.response_type.name; - method.resp_desc = method_information.response_type.descriptor; + method.req_type = method_information.request_type.name; + method.req_desc = method_information.request_type.descriptor; + method.resp_type = method_information.response_type.name; + method.resp_desc = method_information.response_type.descriptor; // new type and descriptor fields - method.req_datatype = method_information.request_type; + method.req_datatype = method_information.request_type; method.resp_datatype = method_information.response_type; { @@ -401,21 +403,21 @@ namespace eCAL ecal_reg_sample.cmd_type = bct_unreg_client; auto& service_identifier = ecal_reg_sample.identifier; - service_identifier.entity_id = m_client_id; + service_identifier.entity_id = m_client_id; service_identifier.process_id = Process::GetProcessID(); - service_identifier.host_name = Process::GetHostName(); + service_identifier.host_name = Process::GetHostName(); auto& service_client = ecal_reg_sample.client; service_client.version = m_client_version; - service_client.pname = Process::GetProcessName(); - service_client.uname = Process::GetUnitName(); - service_client.sname = m_service_name; + service_client.pname = Process::GetProcessName(); + service_client.uname = Process::GetUnitName(); + service_client.sname = m_service_name; return ecal_reg_sample; } // Attempts to retrieve a client session for a given entity ID - bool CServiceClientImpl::GetClientByEntity(const Registration::SEntityId& entity_id_, SClient& client_) + bool CServiceClientImpl::GetClientByEntity(const Registration::SEntityId & entity_id_, SClient & client_) { const std::lock_guard lock(m_client_session_map_mutex); auto iter = m_client_session_map.find(entity_id_); @@ -428,8 +430,8 @@ namespace eCAL // Blocking call to a service with a specified timeout std::pair CServiceClientImpl::CallMethodWithTimeout( - const Registration::SEntityId& entity_id_, SClient& client_, const std::string& method_name_, - const std::string& request_, std::chrono::nanoseconds timeout_) + const Registration::SEntityId & entity_id_, SClient & client_, const std::string & method_name_, + const std::string & request_, std::chrono::nanoseconds timeout_) { if (method_name_.empty()) return { false, SServiceIDResponse() }; @@ -440,7 +442,7 @@ namespace eCAL return { false, SServiceIDResponse() }; // Prepare response data - auto response_data = PrepareInitialResponse(client_, method_name_); + auto response_data = PrepareInitialResponse(client_, method_name_); auto response_callback = CreateResponseCallback(client_, response_data); // Send the service call @@ -481,21 +483,21 @@ namespace eCAL auto state = client_data.client_session->get_state(); Registration::SEntityId entity_id; - entity_id.entity_id = client_data.service_attr.sid; + entity_id.entity_id = client_data.service_attr.sid; entity_id.process_id = client_data.service_attr.pid; - entity_id.host_name = client_data.service_attr.hname; + entity_id.host_name = client_data.service_attr.hname; Registration::SServiceId service_id; service_id.service_name = m_service_name; - service_id.service_id = entity_id; + service_id.service_id = entity_id; - if (!client_data.connected && state == eCAL::service::State::CONNECTED) + if (!client_data.connected && state == ecal_service::State::CONNECTED) { client_data.connected = true; NotifyEventCallback(service_id, eClientEvent::connected); ++it; } - else if (client_data.connected && state == eCAL::service::State::FAILED) + else if (client_data.connected && state == ecal_service::State::FAILED) { client_data.connected = false; NotifyEventCallback(service_id, eClientEvent::disconnected); @@ -508,14 +510,14 @@ namespace eCAL } } - void CServiceClientImpl::IncrementMethodCallCount(const std::string& method_name_) + void CServiceClientImpl::IncrementMethodCallCount(const std::string & method_name_) { const std::lock_guard lock(m_method_information_map_mutex); m_method_call_count_map[method_name_]++; } - void CServiceClientImpl::NotifyEventCallback(const Registration::SServiceId& service_id_, eClientEvent event_type_) + void CServiceClientImpl::NotifyEventCallback(const Registration::SServiceId & service_id_, eClientEvent event_type_) { #ifndef NDEBUG Logging::Log(Logging::log_level_debug1, "CServiceClientImpl::NotifyEventCallback: Notifying event callback for: " + m_service_name + " Event Type: " + to_string(event_type_)); @@ -530,25 +532,25 @@ namespace eCAL m_event_callback(service_id_, callback_data); } - std::shared_ptr CServiceClientImpl::PrepareInitialResponse(const SClient& client_, const std::string& method_name_) + std::shared_ptr CServiceClientImpl::PrepareInitialResponse(const SClient & client_, const std::string & method_name_) { auto data = std::make_shared(); data->response->first = false; - data->response->second.service_method_id.service_id.entity_id = client_.service_attr.sid; + data->response->second.service_method_id.service_id.entity_id = client_.service_attr.sid; data->response->second.service_method_id.service_id.process_id = client_.service_attr.pid; - data->response->second.service_method_id.service_id.host_name = client_.service_attr.hname; + data->response->second.service_method_id.service_id.host_name = client_.service_attr.hname; - data->response->second.service_method_id.service_name = client_.service_attr.sname; - data->response->second.service_method_id.method_name = method_name_; + data->response->second.service_method_id.service_name = client_.service_attr.sname; + data->response->second.service_method_id.method_name = method_name_; data->response->second.call_state = eCallState::none; return data; } - eCAL::service::ClientResponseCallbackT CServiceClientImpl::CreateResponseCallback(const SClient& client_, const std::shared_ptr& response_data_) + ecal_service::ClientResponseCallbackT CServiceClientImpl::CreateResponseCallback(const SClient & client_, const std::shared_ptr&response_data_) { - return [client_, response_data_](const eCAL::service::Error& error, const std::shared_ptr& response_) + return [client_, response_data_](const ecal_service::Error& error, const std::shared_ptr& response_) { const std::lock_guard lock(*response_data_->mutex); if (!*response_data_->block_modifying_response) @@ -556,13 +558,13 @@ namespace eCAL if (error) { response_data_->response->first = false; - response_data_->response->second.error_msg = error.ToString(); + response_data_->response->second.error_msg = error.ToString(); response_data_->response->second.call_state = eCallState::failed; - response_data_->response->second.ret_state = 0; + response_data_->response->second.ret_state = 0; } else { - response_data_->response->first = true; + response_data_->response->first = true; response_data_->response->second = DeserializedResponse(client_, *response_); } } @@ -572,7 +574,7 @@ namespace eCAL } // DeSerializes the response string into a service response - eCAL::SServiceIDResponse CServiceClientImpl::DeserializedResponse(const SClient& client_, const std::string& response_pb_) + eCAL::SServiceIDResponse CServiceClientImpl::DeserializedResponse(const SClient & client_, const std::string & response_pb_) { eCAL::SServiceIDResponse service_reponse; eCAL::Service::Response response; @@ -580,13 +582,13 @@ namespace eCAL { const auto& response_header = response.header; // service/method id - service_reponse.service_method_id.service_id.entity_id = client_.service_attr.sid; + service_reponse.service_method_id.service_id.entity_id = client_.service_attr.sid; service_reponse.service_method_id.service_id.process_id = client_.service_attr.pid; - service_reponse.service_method_id.service_id.host_name = response_header.hname; + service_reponse.service_method_id.service_id.host_name = response_header.hname; // service and method name service_reponse.service_method_id.service_name = response_header.sname; - service_reponse.service_method_id.method_name = response_header.mname; + service_reponse.service_method_id.method_name = response_header.mname; // error message and return state service_reponse.error_msg = response_header.error; @@ -616,4 +618,5 @@ namespace eCAL return service_reponse; } + } } diff --git a/ecal/core/src/service/ecal_service_client_impl.h b/ecal/core/src/service/ecal_service_client_impl.h index 5f69da56fc..987e725924 100644 --- a/ecal/core/src/service/ecal_service_client_impl.h +++ b/ecal/core/src/service/ecal_service_client_impl.h @@ -24,10 +24,10 @@ #include #include #include -#include -#include +#include +#include #include -#include +#include #include "serialization/ecal_serialize_sample_registration.h" #include "serialization/ecal_struct_service.h" @@ -39,132 +39,135 @@ namespace eCAL { - /** - * @brief Service client implementation class. - **/ - class CServiceClientImpl : public std::enable_shared_from_this + ECAL_CORE_NAMESPACE_V6 { - public: - // Factory method to create an instance of the client implementation - static std::shared_ptr CreateInstance( - const std::string& service_name_, const ServiceMethodInformationMapT& method_information_map_, const ClientEventCallbackT& event_callback_); - - private: - // Private constructor to enforce creation through factory method - CServiceClientImpl(const std::string& service_name_, const ServiceMethodInformationMapT& method_information_map_, const ClientEventCallbackT& event_callback_); - - public: - ~CServiceClientImpl(); - - // Retrieve service IDs of all matching services - std::vector GetServiceIDs(); - - // Blocking call to a specific service; returns response as pair - // if a callback is provided call the callback as well - std::pair CallWithCallback( - const Registration::SEntityId& entity_id_, const std::string& method_name_, - const std::string& request_, int timeout_ms_, const ResponseIDCallbackT& response_callback_ = nullptr); - - // Asynchronous call to a specific service using callback - bool CallWithCallbackAsync( - const Registration::SEntityId& entity_id_, const std::string& method_name_, - const std::string& request_, const ResponseIDCallbackT& response_callback_); - - // Check connection state of a specific service - bool IsConnected(const Registration::SEntityId& entity_id_); - - // Called by the registration receiver to process a service registration - void RegisterService(const Registration::SEntityId& entity_id_, const v5::SServiceAttr& service_); - - // Called by the registration provider to get a registration sample - Registration::Sample GetRegistration(); - - // Retrieves the service id - Registration::SServiceId GetServiceId() const; - - // Retrieves the service name - std::string GetServiceName() const; - - // Prevent copy and move operations - CServiceClientImpl(const CServiceClientImpl&) = delete; - CServiceClientImpl& operator=(const CServiceClientImpl&) = delete; - CServiceClientImpl(CServiceClientImpl&&) = delete; - CServiceClientImpl& operator=(CServiceClientImpl&&) = delete; - - private: - // Prepare and retrieve registration and unregistration samples - Registration::Sample GetRegistrationSample(); - Registration::Sample GetUnregistrationSample(); - - // SClient struct representing a client session and its connection state - struct SClient + /** + * @brief Service client implementation class. + **/ + class CServiceClientImpl : public std::enable_shared_from_this { - v5::SServiceAttr service_attr; - std::shared_ptr client_session; - bool connected = false; + public: + // Factory method to create an instance of the client implementation + static std::shared_ptr CreateInstance( + const std::string& service_name_, const ServiceMethodInformationMapT& method_information_map_, const ClientEventCallbackT& event_callback_); + + private: + // Private constructor to enforce creation through factory method + CServiceClientImpl(const std::string& service_name_, const ServiceMethodInformationMapT& method_information_map_, const ClientEventCallbackT& event_callback_); + + public: + ~CServiceClientImpl(); + + // Retrieve service IDs of all matching services + std::vector GetServiceIDs(); + + // Blocking call to a specific service; returns response as pair + // if a callback is provided call the callback as well + std::pair CallWithCallback( + const Registration::SEntityId& entity_id_, const std::string& method_name_, + const std::string& request_, int timeout_ms_, const ResponseIDCallbackT& response_callback_ = nullptr); + + // Asynchronous call to a specific service using callback + bool CallWithCallbackAsync( + const Registration::SEntityId& entity_id_, const std::string& method_name_, + const std::string& request_, const ResponseIDCallbackT& response_callback_); + + // Check connection state of a specific service + bool IsConnected(const Registration::SEntityId& entity_id_); + + // Called by the registration receiver to process a service registration + void RegisterService(const Registration::SEntityId& entity_id_, const v5::SServiceAttr& service_); + + // Called by the registration provider to get a registration sample + Registration::Sample GetRegistration(); + + // Retrieves the service id + Registration::SServiceId GetServiceId() const; + + // Retrieves the service name + std::string GetServiceName() const; + + // Prevent copy and move operations + CServiceClientImpl(const CServiceClientImpl&) = delete; + CServiceClientImpl& operator=(const CServiceClientImpl&) = delete; + CServiceClientImpl(CServiceClientImpl&&) = delete; + CServiceClientImpl& operator=(CServiceClientImpl&&) = delete; + + private: + // Prepare and retrieve registration and unregistration samples + Registration::Sample GetRegistrationSample(); + Registration::Sample GetUnregistrationSample(); + + // SClient struct representing a client session and its connection state + struct SClient + { + v5::SServiceAttr service_attr; + std::shared_ptr client_session; + bool connected = false; + }; + + // Get client for specific entity id + bool GetClientByEntity(const Registration::SEntityId& entity_id_, SClient& client_); + + // Blocking call to a specific service method with timeout + std::pair CallMethodWithTimeout(const Registration::SEntityId& entity_id_, SClient& client_, + const std::string& method_name_, const std::string& request_, std::chrono::nanoseconds timeout_); + + // Update the connection states for client sessions + void UpdateConnectionStates(); + + // Increment method call count for tracking + void IncrementMethodCallCount(const std::string& method_name_); + + // Notify specific event callback + void NotifyEventCallback(const Registration::SServiceId& service_id_, eClientEvent event_type_); + + // SResponseData struct for handling response callbacks + struct SResponseData + { + std::shared_ptr mutex; + std::shared_ptr condition_variable; + std::shared_ptr> response; + std::shared_ptr block_modifying_response; + std::shared_ptr finished; + + SResponseData() : + mutex(std::make_shared()), + condition_variable(std::make_shared()), + response(std::make_shared>(false, SServiceIDResponse())), + block_modifying_response(std::make_shared(false)), + finished(std::make_shared(false)) + {} + }; + + static std::shared_ptr PrepareInitialResponse(const SClient& client_, const std::string& method_name_); + static ecal_service::ClientResponseCallbackT CreateResponseCallback(const SClient& client_, const std::shared_ptr& response_data_); + + static SServiceIDResponse DeserializedResponse(const SClient& client_, const std::string& response_pb_); + + // Client version (incremented for protocol or functionality changes) + static constexpr int m_client_version = 1; + + // Service attributes + std::string m_service_name; + Registration::EntityIdT m_client_id; + + // Client session map and synchronization + using ClientSessionsMapT = std::map; + std::mutex m_client_session_map_mutex; + ClientSessionsMapT m_client_session_map; + + // Method information map (tracks method attributes like data type and description) + std::mutex m_method_information_map_mutex; + ServiceMethodInformationMapT m_method_information_map; + + // Method call count map (tracks number of calls for each method) + using MethodCallCountMapT = std::map; + MethodCallCountMapT m_method_call_count_map; + + // Event callback map and synchronization + std::mutex m_event_callback_mutex; + ClientEventCallbackT m_event_callback; }; - - // Get client for specific entity id - bool GetClientByEntity(const Registration::SEntityId& entity_id_, SClient& client_); - - // Blocking call to a specific service method with timeout - std::pair CallMethodWithTimeout(const Registration::SEntityId& entity_id_, SClient& client_, - const std::string& method_name_, const std::string& request_, std::chrono::nanoseconds timeout_); - - // Update the connection states for client sessions - void UpdateConnectionStates(); - - // Increment method call count for tracking - void IncrementMethodCallCount(const std::string& method_name_); - - // Notify specific event callback - void NotifyEventCallback(const Registration::SServiceId& service_id_, eClientEvent event_type_); - - // SResponseData struct for handling response callbacks - struct SResponseData - { - std::shared_ptr mutex; - std::shared_ptr condition_variable; - std::shared_ptr> response; - std::shared_ptr block_modifying_response; - std::shared_ptr finished; - - SResponseData() : - mutex(std::make_shared()), - condition_variable(std::make_shared()), - response(std::make_shared>(false, SServiceIDResponse())), - block_modifying_response(std::make_shared(false)), - finished(std::make_shared(false)) - {} - }; - - static std::shared_ptr PrepareInitialResponse(const SClient& client_, const std::string& method_name_); - static eCAL::service::ClientResponseCallbackT CreateResponseCallback(const SClient& client_, const std::shared_ptr& response_data_); - - static SServiceIDResponse DeserializedResponse(const SClient& client_, const std::string& response_pb_); - - // Client version (incremented for protocol or functionality changes) - static constexpr int m_client_version = 1; - - // Service attributes - std::string m_service_name; - Registration::EntityIdT m_client_id; - - // Client session map and synchronization - using ClientSessionsMapT = std::map; - std::mutex m_client_session_map_mutex; - ClientSessionsMapT m_client_session_map; - - // Method information map (tracks method attributes like data type and description) - std::mutex m_method_information_map_mutex; - ServiceMethodInformationMapT m_method_information_map; - - // Method call count map (tracks number of calls for each method) - using MethodCallCountMapT = std::map; - MethodCallCountMapT m_method_call_count_map; - - // Event callback map and synchronization - std::mutex m_event_callback_mutex; - ClientEventCallbackT m_event_callback; - }; + } } diff --git a/ecal/core/src/service/ecal_service_client_instance.cpp b/ecal/core/src/service/ecal_service_client_instance.cpp index 524159cd79..814cd73f76 100644 --- a/ecal/core/src/service/ecal_service_client_instance.cpp +++ b/ecal/core/src/service/ecal_service_client_instance.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2024 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,12 +21,12 @@ * @brief eCAL service client instance implementation **/ -#include +#include #include "ecal_service_client_impl.h" namespace eCAL { - CClientInstance::CClientInstance(const Registration::SEntityId& entity_id_, const std::shared_ptr& service_client_id_impl_) + CClientInstance::CClientInstance(const Registration::SEntityId& entity_id_, const std::shared_ptr& service_client_id_impl_) : m_entity_id(entity_id_), m_service_client_impl(service_client_id_impl_) { assert(m_service_client_impl && "service_client_id_impl_ must not be null"); diff --git a/ecal/core/src/service/ecal_service_server.cpp b/ecal/core/src/service/ecal_service_server.cpp index fd0e78b685..af6c958bd1 100644 --- a/ecal/core/src/service/ecal_service_server.cpp +++ b/ecal/core/src/service/ecal_service_server.cpp @@ -29,7 +29,9 @@ namespace eCAL { - CServiceServer::CServiceServer(const std::string& service_name_, const ServerEventCallbackT event_callback_) + ECAL_CORE_NAMESPACE_V6 + { + CServiceServer::CServiceServer(const std::string & service_name_, const ServerEventCallbackT event_callback_) : m_service_server_impl(nullptr) { // create server implementation @@ -48,12 +50,12 @@ namespace eCAL if (g_servicegate() != nullptr) g_servicegate()->Unregister(m_service_server_impl->GetServiceName(), m_service_server_impl); } - CServiceServer::CServiceServer(CServiceServer&& rhs) noexcept + CServiceServer::CServiceServer(CServiceServer && rhs) noexcept : m_service_server_impl(std::move(rhs.m_service_server_impl)) { } - CServiceServer& CServiceServer::operator=(CServiceServer&& rhs) noexcept + CServiceServer & CServiceServer::operator=(CServiceServer && rhs) noexcept { if (this != &rhs) { @@ -62,13 +64,13 @@ namespace eCAL return *this; } - bool CServiceServer::SetMethodCallback(const std::string& method_, const SServiceMethodInformation& method_info_, const MethodInfoCallbackT& callback_) + bool CServiceServer::SetMethodCallback(const std::string & method_, const SServiceMethodInformation & method_info_, const MethodInfoCallbackT & callback_) { if (m_service_server_impl == nullptr) return false; return m_service_server_impl->SetMethodCallback(method_, method_info_, callback_); } - bool CServiceServer::RemoveMethodCallback(const std::string& method_) + bool CServiceServer::RemoveMethodCallback(const std::string & method_) { if (m_service_server_impl == nullptr) return false; return m_service_server_impl->RemoveMethodCallback(method_); @@ -91,4 +93,5 @@ namespace eCAL if (m_service_server_impl == nullptr) return false; return m_service_server_impl->IsConnected(); } + } } diff --git a/ecal/core/src/service/ecal_service_server_impl.cpp b/ecal/core/src/service/ecal_service_server_impl.cpp index b22784d6e1..3adf174511 100644 --- a/ecal/core/src/service/ecal_service_server_impl.cpp +++ b/ecal/core/src/service/ecal_service_server_impl.cpp @@ -33,24 +33,26 @@ namespace eCAL { - // Factory method to create a new instance of CServiceServerImpl - std::shared_ptr CServiceServerImpl::CreateInstance( - const std::string& service_name_, const ServerEventCallbackT& event_callback_) + ECAL_CORE_NAMESPACE_V6 { -#ifndef NDEBUG - Logging::Log(Logging::log_level_debug2, "CServiceServerImpl::CreateInstance: Creating instance of CServiceServerImpl for service: " + service_name_); -#endif - auto instance = std::shared_ptr(new CServiceServerImpl(service_name_, event_callback_)); - if (instance != nullptr) + // Factory method to create a new instance of CServiceServerImpl + std::shared_ptr CServiceServerImpl::CreateInstance( + const std::string & service_name_, const ServerEventCallbackT & event_callback_) { - instance->Start(); + #ifndef NDEBUG + Logging::Log(Logging::log_level_debug2, "CServiceServerImpl::CreateInstance: Creating instance of CServiceServerImpl for service: " + service_name_); + #endif + auto instance = std::shared_ptr(new CServiceServerImpl(service_name_, event_callback_)); + if (instance != nullptr) + { + instance->Start(); + } + return instance; } - return instance; - } // Constructor CServiceServerImpl::CServiceServerImpl(const std::string& service_name_, const ServerEventCallbackT& event_callback_) - : m_created(false), m_service_name(service_name_), m_event_callback(event_callback_) + : m_service_name(service_name_), m_created(false), m_event_callback(event_callback_) { #ifndef NDEBUG Logging::Log(Logging::log_level_debug2, "CServiceServerImpl::CServiceServerImpl: Initializing service server for: " + m_service_name); @@ -66,7 +68,7 @@ namespace eCAL Stop(); } - bool CServiceServerImpl::SetMethodCallback(const std::string& method_, const SServiceMethodInformation& method_info_, const MethodInfoCallbackT& callback_) + bool CServiceServerImpl::SetMethodCallback(const std::string & method_, const SServiceMethodInformation & method_info_, const MethodInfoCallbackT & callback_) { #ifndef NDEBUG Logging::Log(Logging::log_level_debug1, "CServiceServerImpl::SetMethodCallback: Adding method callback for method: " + method_); @@ -80,14 +82,14 @@ namespace eCAL #if 0 // this is how it should look like if we do not use the old type and descriptor fields // update data type and callback - iter->second.method.req_datatype = method_info_.request_type; + iter->second.method.req_datatype = method_info_.request_type; iter->second.method.resp_datatype = method_info_.response_type; - iter->second.callback = callback_; + iter->second.callback = callback_; #else ///////////////////////////////////////////// // old types and descriptors ///////////////////////////////////////////// - iter->second.method.req_type = method_info_.request_type.name; + iter->second.method.req_type = method_info_.request_type.name; iter->second.method.resp_type = method_info_.response_type.name; // we need to check these fields, because the v5 implementation is using SetMethodCallback with partially filled fields @@ -97,7 +99,7 @@ namespace eCAL ///////////////////////////////////////////// // new types, encodings and descriptors ///////////////////////////////////////////// - iter->second.method.req_datatype.name = method_info_.request_type.name; + iter->second.method.req_datatype.name = method_info_.request_type.name; iter->second.method.resp_datatype.name = method_info_.response_type.name; // we need to check these fields, because the v5 implementation is using SetMethodCallback with partially filled fields @@ -124,15 +126,15 @@ namespace eCAL #if 0 // this is how it should look like if we do not use the old type and descriptor fields // set data type and callback - method.method.req_datatype = method_info_.request_type; + method.method.req_datatype = method_info_.request_type; method.method.resp_datatype = method_info_.response_type; - method.callback = callback_; + method.callback = callback_; #else #endif ///////////////////////////////////////////// // old types and descriptors ///////////////////////////////////////////// - method.method.req_type = method_info_.request_type.name; + method.method.req_type = method_info_.request_type.name; method.method.resp_type = method_info_.response_type.name; // we need to check these fields, because the v5 implementation is using SetMethodCallback with partially filled fields @@ -142,7 +144,7 @@ namespace eCAL ///////////////////////////////////////////// // new types, encodings and descriptors ///////////////////////////////////////////// - method.method.req_datatype.name = method_info_.request_type.name; + method.method.req_datatype.name = method_info_.request_type.name; method.method.resp_datatype.name = method_info_.response_type.name; // we need to check these fields, because the v5 implementation is using SetMethodCallback with partially filled fields @@ -164,7 +166,7 @@ namespace eCAL return true; } - bool CServiceServerImpl::RemoveMethodCallback(const std::string& method_) + bool CServiceServerImpl::RemoveMethodCallback(const std::string & method_) { #ifndef NDEBUG Logging::Log(Logging::log_level_debug1, "CServiceServerImpl::RemoveMethodCallback: Removing method callback for method: " + method_); @@ -219,10 +221,10 @@ namespace eCAL { Registration::SServiceId service_id; - service_id.service_id.entity_id = m_service_id; + service_id.service_id.entity_id = m_service_id; service_id.service_id.process_id = Process::GetProcessID(); - service_id.service_id.host_name = Process::GetHostName(); - service_id.service_name = m_service_name; + service_id.service_id.host_name = Process::GetHostName(); + service_id.service_name = m_service_name; return service_id; } @@ -256,22 +258,22 @@ namespace eCAL } // Create callback functions - const eCAL::service::Server::EventCallbackT event_callback = - [weak_me = std::weak_ptr(shared_from_this())](eCAL::service::ServerEventType event, const std::string& message) + const ecal_service::Server::EventCallbackT event_callback = + [weak_me = std::weak_ptr(shared_from_this())](ecal_service::ServerEventType event, const std::string& message) { if (auto me = weak_me.lock()) { Registration::SServiceId service_id; - service_id.service_name = me->m_service_name; + service_id.service_name = me->m_service_name; service_id.service_id.entity_id = me->m_service_id; // TODO: Also fill process ID and hostname? - me->NotifyEventCallback(service_id, event == eCAL::service::ServerEventType::Connected + me->NotifyEventCallback(service_id, event == ecal_service::ServerEventType::Connected ? eServerEvent::connected : eServerEvent::disconnected, message); } }; - const eCAL::service::Server::ServiceCallbackT service_callback = + const ecal_service::Server::ServiceCallbackT service_callback = [weak_me = std::weak_ptr(shared_from_this())](const std::shared_ptr& request, const std::shared_ptr& response) -> int { if (auto me = weak_me.lock()) @@ -352,15 +354,15 @@ namespace eCAL if (server_tcp_port == 0) return ecal_reg_sample; auto& identifier = ecal_reg_sample.identifier; - identifier.entity_id = m_service_id; + identifier.entity_id = m_service_id; identifier.process_id = Process::GetProcessID(); - identifier.host_name = Process::GetHostName(); + identifier.host_name = Process::GetHostName(); auto& service = ecal_reg_sample.service; - service.version = m_server_version; - service.pname = Process::GetProcessName(); - service.uname = Process::GetUnitName(); - service.sname = m_service_name; + service.version = m_server_version; + service.pname = Process::GetProcessName(); + service.uname = Process::GetUnitName(); + service.sname = m_service_name; service.tcp_port_v0 = 0; service.tcp_port_v1 = server_tcp_port; @@ -372,13 +374,13 @@ namespace eCAL method.mname = iter.first; // old type and descriptor fields - method.req_type = iter.second.method.req_type; - method.req_desc = iter.second.method.req_desc; - method.resp_type = iter.second.method.resp_type; - method.resp_desc = iter.second.method.resp_desc; + method.req_type = iter.second.method.req_type; + method.req_desc = iter.second.method.req_desc; + method.resp_type = iter.second.method.resp_type; + method.resp_desc = iter.second.method.resp_desc; // new type and descriptor fields - method.req_datatype = iter.second.method.req_datatype; + method.req_datatype = iter.second.method.req_datatype; method.resp_datatype = iter.second.method.resp_datatype; method.call_count = iter.second.method.call_count; @@ -395,20 +397,20 @@ namespace eCAL ecal_reg_sample.cmd_type = bct_unreg_service; auto& identifier = ecal_reg_sample.identifier; - identifier.entity_id = m_service_id; + identifier.entity_id = m_service_id; identifier.process_id = Process::GetProcessID(); - identifier.host_name = Process::GetHostName(); + identifier.host_name = Process::GetHostName(); auto& service = ecal_reg_sample.service; service.version = m_server_version; - service.pname = Process::GetProcessName(); - service.uname = Process::GetUnitName(); - service.sname = m_service_name; + service.pname = Process::GetProcessName(); + service.uname = Process::GetUnitName(); + service.sname = m_service_name; return ecal_reg_sample; } - int CServiceServerImpl::RequestCallback(const std::string& request_pb_, std::string& response_pb_) + int CServiceServerImpl::RequestCallback(const std::string & request_pb_, std::string & response_pb_) { #ifndef NDEBUG Logging::Log(Logging::log_level_debug2, "CServiceServerImpl::RequestCallback: Processing request callback for: " + m_service_name); @@ -419,7 +421,7 @@ namespace eCAL auto& response_header = response.header; response_header.hname = Process::GetHostName(); response_header.sname = m_service_name; - response_header.sid = std::to_string(m_service_id); // TODO: Service ID currently defined as string, should be integer as well + response_header.sid = std::to_string(m_service_id); // TODO: Service ID currently defined as string, should be integer as well // try to parse request Service::Request request; @@ -494,7 +496,7 @@ namespace eCAL return 0; } - void CServiceServerImpl::NotifyEventCallback(const Registration::SServiceId& service_id_, eServerEvent event_type_, const std::string& /*message_*/) + void CServiceServerImpl::NotifyEventCallback(const Registration::SServiceId & service_id_, eServerEvent event_type_, const std::string& /*message_*/) { #ifndef NDEBUG Logging::Log(Logging::log_level_debug1, "CServiceServerImpl::NotifyEventCallback: Notifying event callback for: " + m_service_name + " Event Type: " + to_string(event_type_)); @@ -508,4 +510,5 @@ namespace eCAL callback_data.time = std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); m_event_callback(service_id_, callback_data); } + } } diff --git a/ecal/core/src/service/ecal_service_server_impl.h b/ecal/core/src/service/ecal_service_server_impl.h index dcbef69b8d..ca118b081c 100644 --- a/ecal/core/src/service/ecal_service_server_impl.h +++ b/ecal/core/src/service/ecal_service_server_impl.h @@ -23,10 +23,11 @@ #pragma once +#include #include -#include -#include -#include +#include +#include +#include #include "serialization/ecal_serialize_sample_registration.h" #include "serialization/ecal_struct_service.h" @@ -39,88 +40,91 @@ namespace eCAL { - /** - * @brief Implementation class for eCAL service server. - */ - class CServiceServerImpl : public std::enable_shared_from_this + ECAL_CORE_NAMESPACE_V6 { - public: - // Factory method to create an instance of the client implementation - static std::shared_ptr CreateInstance( - const std::string& service_name_, const ServerEventCallbackT& event_callback_); + /** + * @brief Implementation class for eCAL service server. + */ + class CServiceServerImpl : public std::enable_shared_from_this + { + public: + // Factory method to create an instance of the client implementation + static std::shared_ptr CreateInstance( + const std::string& service_name_, const ServerEventCallbackT& event_callback_); - private: - // Private constructor to enforce creation through factory method - CServiceServerImpl(const std::string& service_name_, const ServerEventCallbackT& event_callback_); + private: + // Private constructor to enforce creation through factory method + CServiceServerImpl(const std::string& service_name_, const ServerEventCallbackT& event_callback_); - public: - ~CServiceServerImpl(); + public: + ~CServiceServerImpl(); - bool SetMethodCallback(const std::string& method_, const SServiceMethodInformation& method_info_, const MethodInfoCallbackT& callback_); - bool RemoveMethodCallback(const std::string& method_); + bool SetMethodCallback(const std::string& method_, const SServiceMethodInformation& method_info_, const MethodInfoCallbackT& callback_); + bool RemoveMethodCallback(const std::string& method_); - // Check connection state of a specific service - bool IsConnected() const; + // Check connection state of a specific service + bool IsConnected() const; - // Called by the registration receiver to process a client registration - void RegisterClient(const std::string& key_, const v5::SClientAttr& client_); + // Called by the registration receiver to process a client registration + void RegisterClient(const std::string& key_, const v5::SClientAttr& client_); - // Called by the registration provider to get a registration sample - Registration::Sample GetRegistration(); + // Called by the registration provider to get a registration sample + Registration::Sample GetRegistration(); - // Retrieves the service id - Registration::SServiceId GetServiceId() const; + // Retrieves the service id + Registration::SServiceId GetServiceId() const; - // Retrieves the service name - std::string GetServiceName() const; + // Retrieves the service name + std::string GetServiceName() const; - // Prevent copy and move operations - CServiceServerImpl(const CServiceServerImpl&) = delete; - CServiceServerImpl& operator=(const CServiceServerImpl&) = delete; - CServiceServerImpl(CServiceServerImpl&&) = delete; - CServiceServerImpl& operator=(CServiceServerImpl&&) = delete; + // Prevent copy and move operations + CServiceServerImpl(const CServiceServerImpl&) = delete; + CServiceServerImpl& operator=(const CServiceServerImpl&) = delete; + CServiceServerImpl(CServiceServerImpl&&) = delete; + CServiceServerImpl& operator=(CServiceServerImpl&&) = delete; - private: - // Start/Stop server - void Start(); - void Stop(); + private: + // Start/Stop server + void Start(); + void Stop(); - // Prepare and retrieve registration and unregistration samples - Registration::Sample GetRegistrationSample(); - Registration::Sample GetUnregistrationSample(); + // Prepare and retrieve registration and unregistration samples + Registration::Sample GetRegistrationSample(); + Registration::Sample GetUnregistrationSample(); - // Request and event callback methods - int RequestCallback(const std::string& request_pb_, std::string& response_pb_); - void NotifyEventCallback(const Registration::SServiceId& service_id_, eServerEvent event_type_, const std::string& message_); + // Request and event callback methods + int RequestCallback(const std::string& request_pb_, std::string& response_pb_); + void NotifyEventCallback(const Registration::SServiceId& service_id_, eServerEvent event_type_, const std::string& message_); - // Server version (incremented for protocol or functionality changes) - static constexpr int m_server_version = 1; + // Server version (incremented for protocol or functionality changes) + static constexpr int m_server_version = 1; - // Server attributes - std::string m_service_name; - Registration::EntityIdT m_service_id; + // Server attributes + std::string m_service_name; + Registration::EntityIdT m_service_id; - // Server connection state and synchronization - mutable std::mutex m_connected_mutex; // mutex protecting m_connected (modified by the event callbacks in another thread) - bool m_connected = false; - std::atomic m_created; + // Server connection state and synchronization + mutable std::mutex m_connected_mutex; // mutex protecting m_connected (modified by the event callbacks in another thread) + bool m_connected = false; + std::atomic m_created; - // Server method map and synchronization - struct SMethod - { - Service::Method method; - MethodInfoCallbackT callback; - }; + // Server method map and synchronization + struct SMethod + { + Service::Method method; + MethodInfoCallbackT callback; + }; - using MethodMapT = std::map; - std::mutex m_method_map_mutex; - MethodMapT m_method_map; + using MethodMapT = std::map; + std::mutex m_method_map_mutex; + MethodMapT m_method_map; - // Event callback and synchronization - std::mutex m_event_callback_mutex; - ServerEventCallbackT m_event_callback; + // Event callback and synchronization + std::mutex m_event_callback_mutex; + ServerEventCallbackT m_event_callback; - // Server interface - std::shared_ptr m_tcp_server; - }; + // Server interface + std::shared_ptr m_tcp_server; + }; + } } diff --git a/ecal/core/src/service/ecal_service_singleton_manager.cpp b/ecal/core/src/service/ecal_service_singleton_manager.cpp index 72fe9f10ad..62965a708e 100644 --- a/ecal/core/src/service/ecal_service_singleton_manager.cpp +++ b/ecal/core/src/service/ecal_service_singleton_manager.cpp @@ -30,28 +30,28 @@ namespace eCAL { namespace service { - eCAL::service::LoggerT ecal_logger(const std::string& node_name) + ecal_service::LoggerT ecal_logger(const std::string& node_name) { - return [node_name](const LogLevel log_level, const std::string& message) + return [node_name](const ecal_service::LogLevel log_level, const std::string& message) { switch (log_level) { - case LogLevel::DebugVerbose: + case ecal_service::LogLevel::DebugVerbose: eCAL::Logging::Log(eCAL::Logging::log_level_debug4, "[" + node_name + "] " + message); break; - case LogLevel::Debug: + case ecal_service::LogLevel::Debug: eCAL::Logging::Log(eCAL::Logging::log_level_debug1, "[" + node_name + "] " + message); break; - case LogLevel::Info: + case ecal_service::LogLevel::Info: eCAL::Logging::Log(eCAL::Logging::log_level_debug1, "[" + node_name + "] " + message); break; - case LogLevel::Warning: + case ecal_service::LogLevel::Warning: eCAL::Logging::Log(eCAL::Logging::log_level_warning, "[" + node_name + "] " + message); break; - case LogLevel::Error: + case ecal_service::LogLevel::Error: eCAL::Logging::Log(eCAL::Logging::log_level_error, "[" + node_name + "] " + message); break; - case LogLevel::Fatal: + case ecal_service::LogLevel::Fatal: eCAL::Logging::Log(eCAL::Logging::log_level_fatal, "[" + node_name + "] " + message); break; default: @@ -85,7 +85,7 @@ namespace eCAL // Public API //////////////////////////////////////////////////////////// - std::shared_ptr ServiceManager::get_client_manager() + std::shared_ptr ServiceManager::get_client_manager() { // Quickly check the atomic stopped boolean before actually locking the // mutex. It can theoretically change before we got mutex access, so we @@ -103,7 +103,7 @@ namespace eCAL // Create the client manager, if it didn't exist, yet if (!m_client_manager) - m_client_manager = eCAL::service::ClientManager::create(m_io_context, ecal_logger("Service Client")); + m_client_manager = ecal_service::ClientManager::create(m_io_context, ecal_logger("Service Client")); // Start io threads, if necessary if (m_io_threads.empty()) @@ -122,7 +122,7 @@ namespace eCAL return nullptr; } - std::shared_ptr ServiceManager::get_server_manager() + std::shared_ptr ServiceManager::get_server_manager() { // Quickly check the atomic stopped boolean before actually locking the // mutex. It can theoretically change before we got mutex access, so we @@ -140,7 +140,7 @@ namespace eCAL // Create the server manager, if it didn't exit, yet if (!m_server_manager) - m_server_manager = eCAL::service::ServerManager::create(m_io_context, ecal_logger("Service Server")); + m_server_manager = ecal_service::ServerManager::create(m_io_context, ecal_logger("Service Server")); // Start io threads, if necessary if (m_io_threads.empty()) diff --git a/ecal/core/src/service/ecal_service_singleton_manager.h b/ecal/core/src/service/ecal_service_singleton_manager.h index 926587a611..9b8bb2f582 100644 --- a/ecal/core/src/service/ecal_service_singleton_manager.h +++ b/ecal/core/src/service/ecal_service_singleton_manager.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2024 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,8 +21,8 @@ #include #include -#include -#include +#include +#include #include #include @@ -59,8 +59,8 @@ namespace eCAL // Public API //////////////////////////////////////////////////////////// public: - std::shared_ptr get_client_manager(); - std::shared_ptr get_server_manager(); + std::shared_ptr get_client_manager(); + std::shared_ptr get_server_manager(); void stop(); void reset(); @@ -77,8 +77,8 @@ namespace eCAL std::shared_ptr m_io_context; std::vector> m_io_threads; - std::shared_ptr m_client_manager; - std::shared_ptr m_server_manager; + std::shared_ptr m_client_manager; + std::shared_ptr m_server_manager; }; } diff --git a/ecal/core/src/service/ecal_servicegate.cpp b/ecal/core/src/service/ecal_servicegate.cpp index 216f84eb8c..fef8810ab5 100644 --- a/ecal/core/src/service/ecal_servicegate.cpp +++ b/ecal/core/src/service/ecal_servicegate.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2024 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -57,18 +57,18 @@ namespace eCAL m_created = false; } - bool CServiceGate::Register(const std::string& service_name_, const std::shared_ptr& server_) + bool CServiceGate::Register(const std::string& service_name_, const std::shared_ptr& server_) { if(!m_created) return(false); // register internal service const std::unique_lock lock(m_service_server_map_mutex); - m_service_server_map.emplace(std::pair>(service_name_, server_)); + m_service_server_map.emplace(std::pair>(service_name_, server_)); return(true); } - bool CServiceGate::Unregister(const std::string& service_name_, const std::shared_ptr& server_) + bool CServiceGate::Unregister(const std::string& service_name_, const std::shared_ptr& server_) { if (!m_created) return(false); bool ret_state = false; diff --git a/ecal/core/src/service/ecal_servicegate.h b/ecal/core/src/service/ecal_servicegate.h index 8dc75429be..64459d024b 100644 --- a/ecal/core/src/service/ecal_servicegate.h +++ b/ecal/core/src/service/ecal_servicegate.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2024 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ #pragma once +#include #include "ecal_def.h" #include "serialization/ecal_struct_sample_registration.h" @@ -34,8 +35,14 @@ namespace eCAL { - class CServiceServerImpl; + ECAL_CORE_NAMESPACE_V6 + { + class CServiceServerImpl; + } +} +namespace eCAL +{ class CServiceGate { public: @@ -45,15 +52,15 @@ namespace eCAL void Start(); void Stop(); - bool Register (const std::string& service_name_, const std::shared_ptr& server_); - bool Unregister(const std::string& service_name_, const std::shared_ptr& server_); + bool Register (const std::string& service_name_, const std::shared_ptr& server_); + bool Unregister(const std::string& service_name_, const std::shared_ptr& server_); void GetRegistrations(Registration::SampleList& reg_sample_list_); protected: static std::atomic m_created; - using ServiceNameServiceImplMapT = std::multimap>; + using ServiceNameServiceImplMapT = std::multimap>; std::shared_timed_mutex m_service_server_map_mutex; ServiceNameServiceImplMapT m_service_server_map; }; diff --git a/ecal/core/src/pubsub/ecal_publisher_v5.cpp b/ecal/core/src/v5/pubsub/ecal_publisher.cpp similarity index 97% rename from ecal/core/src/pubsub/ecal_publisher_v5.cpp rename to ecal/core/src/v5/pubsub/ecal_publisher.cpp index 684586a88f..7f80acdbb7 100644 --- a/ecal/core/src/pubsub/ecal_publisher_v5.cpp +++ b/ecal/core/src/v5/pubsub/ecal_publisher.cpp @@ -22,13 +22,13 @@ **/ #include -#include +#include #include "ecal_globals.h" -#include "ecal_publisher_impl.h" +#include #include "ecal_config_internal.h" -#include "config/builder/writer_attribute_builder.h" +#include #include "readwrite/ecal_writer_buffer_payload.h" #include @@ -39,7 +39,7 @@ namespace eCAL { - namespace v5 + ECAL_CORE_NAMESPACE_V5 { CPublisher::CPublisher() : m_publisher_impl(nullptr), diff --git a/ecal/core/src/pubsub/ecal_subscriber_v5.cpp b/ecal/core/src/v5/pubsub/ecal_subscriber.cpp similarity index 97% rename from ecal/core/src/pubsub/ecal_subscriber_v5.cpp rename to ecal/core/src/v5/pubsub/ecal_subscriber.cpp index bc65c114fb..56aab07222 100644 --- a/ecal/core/src/pubsub/ecal_subscriber_v5.cpp +++ b/ecal/core/src/v5/pubsub/ecal_subscriber.cpp @@ -21,13 +21,15 @@ * @brief common data subscriber for eCAL **/ +#include + #include -#include +#include #include "ecal_globals.h" -#include "ecal_subscriber_impl.h" +#include -#include "config/builder/reader_attribute_builder.h" +#include #include "ecal_config_internal.h" #include @@ -38,7 +40,7 @@ namespace eCAL { - namespace v5 + ECAL_CORE_NAMESPACE_V5 { CSubscriber::CSubscriber() : m_subscriber_impl(nullptr) diff --git a/ecal/core/src/service/ecal_service_client_v5.cpp b/ecal/core/src/v5/service/ecal_service_client.cpp similarity index 96% rename from ecal/core/src/service/ecal_service_client_v5.cpp rename to ecal/core/src/v5/service/ecal_service_client.cpp index d9e143983f..cf017316dc 100644 --- a/ecal/core/src/service/ecal_service_client_v5.cpp +++ b/ecal/core/src/v5/service/ecal_service_client.cpp @@ -21,15 +21,17 @@ * @brief eCAL service client interface (deprecated eCAL5 version) **/ -#include -#include -#include +#include "ecal_service_client_impl.h" + +#include -#include "ecal_service_client_v5_impl.h" +#include +#include +#include namespace eCAL { - namespace v5 + ECAL_CORE_NAMESPACE_V5 { CServiceClient::CServiceClient() : m_service_client_impl(nullptr) diff --git a/ecal/core/src/service/ecal_service_client_v5_impl.cpp b/ecal/core/src/v5/service/ecal_service_client_impl.cpp similarity index 98% rename from ecal/core/src/service/ecal_service_client_v5_impl.cpp rename to ecal/core/src/v5/service/ecal_service_client_impl.cpp index 1cb545c8ea..1a56398ca1 100644 --- a/ecal/core/src/service/ecal_service_client_v5_impl.cpp +++ b/ecal/core/src/v5/service/ecal_service_client_impl.cpp @@ -21,7 +21,8 @@ * @brief eCAL service client implementation (deprecated eCAL5 version) **/ -#include "ecal_service_client_v5_impl.h" +#include "ecal_service_client_impl.h" +#include #include namespace @@ -50,7 +51,7 @@ namespace namespace eCAL { - namespace v5 + ECAL_CORE_NAMESPACE_V5 { CServiceClientImpl::CServiceClientImpl() : m_service_client_impl(nullptr) @@ -119,7 +120,7 @@ namespace eCAL }; // Create the new service client implementation with the event callback - m_service_client_impl = std::make_shared( + m_service_client_impl = std::make_shared( service_name_, method_information_map_, event_callback diff --git a/ecal/core/src/service/ecal_service_client_v5_impl.h b/ecal/core/src/v5/service/ecal_service_client_impl.h similarity index 95% rename from ecal/core/src/service/ecal_service_client_v5_impl.h rename to ecal/core/src/v5/service/ecal_service_client_impl.h index 4f0267c9e1..85ba2fb23b 100644 --- a/ecal/core/src/service/ecal_service_client_v5_impl.h +++ b/ecal/core/src/v5/service/ecal_service_client_impl.h @@ -24,9 +24,10 @@ #pragma once #include +#include #include -#include -#include +#include +#include #include #include @@ -35,7 +36,7 @@ namespace eCAL { - namespace v5 + ECAL_CORE_NAMESPACE_V5 { /** * @brief Service client implementation class. @@ -102,7 +103,7 @@ namespace eCAL private: // Pointer to the underlying service client implementation - std::shared_ptr m_service_client_impl; + std::shared_ptr m_service_client_impl; // Host name filter for the service client std::string m_host_name; diff --git a/ecal/core/src/service/ecal_service_server_v5.cpp b/ecal/core/src/v5/service/ecal_service_server.cpp similarity index 96% rename from ecal/core/src/service/ecal_service_server_v5.cpp rename to ecal/core/src/v5/service/ecal_service_server.cpp index 10bdd76b1a..32c8c1c07c 100644 --- a/ecal/core/src/service/ecal_service_server_v5.cpp +++ b/ecal/core/src/v5/service/ecal_service_server.cpp @@ -21,17 +21,17 @@ * @brief eCAL service server interface (deprecated eCAL5 version) **/ +#include #include -#include #include -#include "ecal_servicegate.h" +#include "service/ecal_servicegate.h" #include "ecal_global_accessors.h" -#include "ecal_service_server_v5_impl.h" +#include "ecal_service_server_impl.h" namespace eCAL { - namespace v5 + ECAL_CORE_NAMESPACE_V5 { CServiceServer::CServiceServer() : m_service_server_impl(nullptr) diff --git a/ecal/core/src/service/ecal_service_server_v5_impl.cpp b/ecal/core/src/v5/service/ecal_service_server_impl.cpp similarity index 97% rename from ecal/core/src/service/ecal_service_server_v5_impl.cpp rename to ecal/core/src/v5/service/ecal_service_server_impl.cpp index b47d3200e1..e83678bdca 100644 --- a/ecal/core/src/service/ecal_service_server_v5_impl.cpp +++ b/ecal/core/src/v5/service/ecal_service_server_impl.cpp @@ -23,11 +23,11 @@ #include -#include "ecal_service_server_v5_impl.h" +#include "ecal_service_server_impl.h" namespace eCAL { - namespace v5 + ECAL_CORE_NAMESPACE_V5 { CServiceServerImpl::CServiceServerImpl() : m_service_server_impl(nullptr) @@ -77,7 +77,7 @@ namespace eCAL } }; - m_service_server_impl = std::make_shared(service_name_, event_callback); + m_service_server_impl = std::make_shared(service_name_, event_callback); Logging::Log(Logging::log_level_debug1, "v5::CServiceServerImpl: Service server created with name: " + service_name_); return true; } diff --git a/ecal/core/src/service/ecal_service_server_v5_impl.h b/ecal/core/src/v5/service/ecal_service_server_impl.h similarity index 92% rename from ecal/core/src/service/ecal_service_server_v5_impl.h rename to ecal/core/src/v5/service/ecal_service_server_impl.h index 313e076756..71cba57562 100644 --- a/ecal/core/src/service/ecal_service_server_v5_impl.h +++ b/ecal/core/src/v5/service/ecal_service_server_impl.h @@ -24,16 +24,17 @@ #pragma once #include +#include #include -#include -#include +#include +#include #include #include namespace eCAL { - namespace v5 + ECAL_CORE_NAMESPACE_V5 { class CServiceServerImpl { @@ -64,7 +65,7 @@ namespace eCAL private: // Pointer to the underlying service server implementation - std::shared_ptr m_service_server_impl; + std::shared_ptr m_service_server_impl; // Mutex and map for managing event callbacks std::mutex m_event_callback_map_mutex; diff --git a/ecal/samples/cpp/benchmarks/datarate_rec/src/datarate_rec.cpp b/ecal/samples/cpp/benchmarks/datarate_rec/src/datarate_rec.cpp index 61de1d3ec0..b44464b679 100644 --- a/ecal/samples/cpp/benchmarks/datarate_rec/src/datarate_rec.cpp +++ b/ecal/samples/cpp/benchmarks/datarate_rec/src/datarate_rec.cpp @@ -25,7 +25,7 @@ #include #include -#include +#include // main entry int main(int argc, char** argv) diff --git a/ecal/samples/cpp/benchmarks/datarate_snd/src/datarate_snd.cpp b/ecal/samples/cpp/benchmarks/datarate_snd/src/datarate_snd.cpp index c997e9b638..6613412b23 100644 --- a/ecal/samples/cpp/benchmarks/datarate_snd/src/datarate_snd.cpp +++ b/ecal/samples/cpp/benchmarks/datarate_snd/src/datarate_snd.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2024 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ #include #include -#include +#include // main entry int main(int argc, char **argv) diff --git a/ecal/samples/cpp/benchmarks/latency_snd/src/binary_payload_writer.h b/ecal/samples/cpp/benchmarks/latency_snd/src/binary_payload_writer.h index bea3b8575e..b2a4a75fff 100644 --- a/ecal/samples/cpp/benchmarks/latency_snd/src/binary_payload_writer.h +++ b/ecal/samples/cpp/benchmarks/latency_snd/src/binary_payload_writer.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,7 +19,7 @@ #pragma once -#include +#include #include // a binary payload diff --git a/ecal/samples/cpp/benchmarks/performance_rec/src/performance_rec.cpp b/ecal/samples/cpp/benchmarks/performance_rec/src/performance_rec.cpp index a9acbae6f4..2477e8c4be 100644 --- a/ecal/samples/cpp/benchmarks/performance_rec/src/performance_rec.cpp +++ b/ecal/samples/cpp/benchmarks/performance_rec/src/performance_rec.cpp @@ -18,7 +18,7 @@ */ #include -#include +#include #include #include diff --git a/ecal/samples/cpp/benchmarks/performance_snd/src/binary_payload_writer.h b/ecal/samples/cpp/benchmarks/performance_snd/src/binary_payload_writer.h index bea3b8575e..b2a4a75fff 100644 --- a/ecal/samples/cpp/benchmarks/performance_snd/src/binary_payload_writer.h +++ b/ecal/samples/cpp/benchmarks/performance_snd/src/binary_payload_writer.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,7 +19,7 @@ #pragma once -#include +#include #include // a binary payload diff --git a/ecal/samples/cpp/benchmarks/performance_snd/src/performance_snd.cpp b/ecal/samples/cpp/benchmarks/performance_snd/src/performance_snd.cpp index 158bc6d60a..5aaa42bdf8 100644 --- a/ecal/samples/cpp/benchmarks/performance_snd/src/performance_snd.cpp +++ b/ecal/samples/cpp/benchmarks/performance_snd/src/performance_snd.cpp @@ -18,7 +18,7 @@ */ #include -#include +#include #include #include diff --git a/ecal/samples/cpp/benchmarks/perftool/src/publisher.h b/ecal/samples/cpp/benchmarks/perftool/src/publisher.h index 6d56d43bcb..207fd94581 100644 --- a/ecal/samples/cpp/benchmarks/perftool/src/publisher.h +++ b/ecal/samples/cpp/benchmarks/perftool/src/publisher.h @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/ecal/samples/cpp/benchmarks/perftool/src/subscriber.h b/ecal/samples/cpp/benchmarks/perftool/src/subscriber.h index a30b368e91..e837cec5b0 100644 --- a/ecal/samples/cpp/benchmarks/perftool/src/subscriber.h +++ b/ecal/samples/cpp/benchmarks/perftool/src/subscriber.h @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include diff --git a/ecal/samples/cpp/benchmarks/pubsub_throughput/src/binary_payload_writer.h b/ecal/samples/cpp/benchmarks/pubsub_throughput/src/binary_payload_writer.h index bea3b8575e..b2a4a75fff 100644 --- a/ecal/samples/cpp/benchmarks/pubsub_throughput/src/binary_payload_writer.h +++ b/ecal/samples/cpp/benchmarks/pubsub_throughput/src/binary_payload_writer.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,7 +19,7 @@ #pragma once -#include +#include #include // a binary payload diff --git a/ecal/samples/cpp/misc/timer/src/timer.cpp b/ecal/samples/cpp/misc/timer/src/timer.cpp index e7495ffce1..8fb22ea0d7 100644 --- a/ecal/samples/cpp/misc/timer/src/timer.cpp +++ b/ecal/samples/cpp/misc/timer/src/timer.cpp @@ -18,7 +18,7 @@ */ #include -#include +#include #include #include diff --git a/ecal/samples/cpp/pubsub/binary/ping/src/ping.cpp b/ecal/samples/cpp/pubsub/binary/ping/src/ping.cpp index 2e2c2f4861..bc49996185 100644 --- a/ecal/samples/cpp/pubsub/binary/ping/src/ping.cpp +++ b/ecal/samples/cpp/pubsub/binary/ping/src/ping.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2024 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ */ #include -#include +#include #include diff --git a/ecal/samples/cpp/pubsub/binary/pong/src/pong.cpp b/ecal/samples/cpp/pubsub/binary/pong/src/pong.cpp index 8422eb3949..20aa71e9df 100644 --- a/ecal/samples/cpp/pubsub/binary/pong/src/pong.cpp +++ b/ecal/samples/cpp/pubsub/binary/pong/src/pong.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2024 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ */ #include -#include +#include #include diff --git a/ecal/service/ecal_service/CMakeLists.txt b/ecal/service/ecal_service/CMakeLists.txt index 63d1ff833e..f4b20103c0 100644 --- a/ecal/service/ecal_service/CMakeLists.txt +++ b/ecal/service/ecal_service/CMakeLists.txt @@ -13,15 +13,15 @@ find_package(asio REQUIRED) # Public API include directory set (includes - include/ecal/service/client_manager.h - include/ecal/service/client_session.h - include/ecal/service/client_session_types.h - include/ecal/service/error.h - include/ecal/service/logger.h - include/ecal/service/server.h - include/ecal/service/server_manager.h - include/ecal/service/server_session_types.h - include/ecal/service/state.h + include/ecal_service/client_manager.h + include/ecal_service/client_session.h + include/ecal_service/client_session_types.h + include/ecal_service/error.h + include/ecal_service/logger.h + include/ecal_service/server.h + include/ecal_service/server_manager.h + include/ecal_service/server_session_types.h + include/ecal_service/state.h ) # Private source files diff --git a/ecal/service/ecal_service/include/ecal/service/client_manager.h b/ecal/service/ecal_service/include/ecal/service/client_manager.h deleted file mode 100644 index 0bb903c947..0000000000 --- a/ecal/service/ecal_service/include/ecal/service/client_manager.h +++ /dev/null @@ -1,206 +0,0 @@ -/* ========================= eCAL LICENSE ================================= - * - * Copyright (C) 2016 - 2019 Continental Corporation - * - * 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. - * - * ========================= eCAL LICENSE ================================= -*/ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include // IWYU pragma: export - -namespace eCAL -{ - namespace service - { - /** - * @brief Manager for eCAL::service::ClientSession instances - * - * The ClientManager is used to create and stop ClientSessions. It keeps - * track of ClientSession instances that it created. The user doesn't need - * to manage the Sessions manually, e.g. for stopping them from a central - * place. - * - * The ClientManager is only available as shared_ptr. It must be created - * using the static create() method. - * - * - Upon creation, the ClientManager will create a work object for the - * given io_context. This will keep the io_context alive, even if there - * are no clients running. - * - * - For creating a client, the create_client() method must be used. This - * will create a new client instance and return a shared_ptr to it. - * - * - For stopping all clients, the stop() method must be used. This - * will stop all clients and delete the internal work object, so the - * thread executing it can be joined. - * - * ========================================================================= - * _Important_: Do not stop the io_context. This may cause undefined behavior. - * Instead, stop the client manager and wait for the io_context - * to run out of work on its own. - * ========================================================================= - * - * Example code: - * - * @code {.cpp} - * - * // Create the io_context - * auto io_context = std::make_shared(); - * - * // Create a thread for the io_context - * std::thread io_context_thread([&io_context]() { io_context->run(); }); - * - * // Create a client manager - * auto client_manager = eCAL::service::ClientManager::create(io_context, ...); - * - * // Create actual client instances - * auto client1 = client_manager->create_client(...) - * auto client2 = client_manager->create_client(...) - * - * // DO STUFF - * - * // Stop ALL clients from a common place - * client_manager->stop(); - * - * // Join the io_context thread. The io_context does not need to be stopped. - * io_context_thread.join(); - * - * @endcode - * - */ - class ClientManager : public std::enable_shared_from_this - { - /////////////////////////////////////////////////////// - // Constructor, Destructor, Create - /////////////////////////////////////////////////////// - public: - /** - * @brief Create a new ClientManager instance, that can be used to create and stop ClientSession instances. - * - * After creation, the ClientManager will create a work object for the - * given io_context. This will keep the io_context alive, even if there - * are no clients running. When stopping the clients, that work object - * will be deleted and the io_context will run out of work on its own. - * - * @param io_context The io context, that will be used for all client sessions - * @param logger A logger-function that will be used for by all client sessions - * - * @return A shared_ptr to the newly created ClientManager instance - */ - static std::shared_ptr create(const std::shared_ptr& io_context, const LoggerT& logger = default_logger("Service Client")); - - // delete copy and move constructors and assign operators - ClientManager(const ClientManager&) = delete; // Copy construct - ClientManager(ClientManager&&) = delete; // Move construct - ClientManager& operator=(const ClientManager&) = delete; // Copy assign - ClientManager& operator=(ClientManager&&) = delete; // Move assign - - // Constructor, Destructor - protected: - ClientManager(const std::shared_ptr& io_context, const LoggerT& logger); - - public: - ~ClientManager(); - - /////////////////////////////////////////////////////// - // Public API - /////////////////////////////////////////////////////// - public: - /** - * @brief Create a new ClienSession instance, which is managed by this client manager. - * - * The ClientSession will immediatelly connect to the server through the - * given address and port. The protocol version must match the server, - * especially when version 0 (the legacy buggy protocol) is used. Future - * versions are expected to be compatible to each other. - * - * The Event Callback will be called, when the client has connected to the - * server or disconnected from it. - * - * The new Client Session will be managed by the ClientManager and can be - * stopped from this central place. - * - * @param protocol_version The protocol version to use for the client session. If 0, the legacy buggy protocol will be used. - * @param server_list A list of endpoints to connect to. Must not be empty. The endpoints will be tried in the given order until a working endpoint is found. - * @param event_callback The callback, that will be called, when the client has connected to the server or disconnected from it. The callback will be executed in the io_context thread. - * - * @return A shared_ptr to the newly created ClientSession instance - */ - std::shared_ptr create_client(std::uint8_t protocol_version - , const std::vector>& server_list - , const ClientSession::EventCallbackT& event_callback); - - /** - * @brief Returns the number of managed client sessions - * - * @return The number of managed client sessions - */ - size_t client_count() const; - - /** - * @brief Stops the client manager and all managed client sessions - * - * This will stop all managed client sessions and delete the internal - * work object, so the thread executing the io_context can be joined. - * The io context will run out of work on its own. - * - * Once stopped, the client manager cannot be used anymore. It must be - * deleted and a new one must be created. - * - * Make sure, that the io_context is executed by a thread again, when - * creating a new client manager. - */ - void stop(); - - /** - * @brief Returns true, if the client manager is stopped - * - * If stopped, the client manager cannot be restarted. Create a new one - * instead. Make sure, that the io_context is executed by a thread again, - * when creating a new client manager. - * - * @return true, if the client_manager is stopped. False otherwise. - */ - bool is_stopped() const; - - /////////////////////////////////////////////////////// - // Member variables - /////////////////////////////////////////////////////// - private: - const std::shared_ptr io_context_; //!< Reference to the asio io_context - const LoggerT logger_; //!< Logger for all clients - - mutable std::mutex client_manager_mutex_; //!< Mutex protecting the entire class - bool stopped_; //!< Flag indicating, if the manager is stopped - std::unique_ptr work_; //!< Work object to keep the io_context alive. Will be deleted, when the manager is stopped. - std::map> sessions_; //!< Map of all managed client sessions. The raw_ptr is used as key, because it is unique for each client. The weak_ptr is used to actually access the client object, because the client may already be dead and the raw ptr would be dangling in that case. - }; - - } -} diff --git a/ecal/service/ecal_service/include/ecal/service/client_session.h b/ecal/service/ecal_service/include/ecal/service/client_session.h deleted file mode 100644 index 6b9b7f52de..0000000000 --- a/ecal/service/ecal_service/include/ecal/service/client_session.h +++ /dev/null @@ -1,305 +0,0 @@ -/* ========================= eCAL LICENSE ================================= - * - * Copyright (C) 2016 - 2019 Continental Corporation - * - * 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. - * - * ========================= eCAL LICENSE ================================= -*/ - -#pragma once - -#include -#include -#include -#include -#include -#include - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable: 4834) -#endif -#include -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -#include -#include -#include -#include - -namespace eCAL -{ - namespace service - { - // Forward declarations - class ClientSessionBase; - - /** - * @brief The eCAL::sercice::ClientSession class represents the binary service client session. - * - * The ClientSession can connect to exactly one service server. For multiple - * connections, multiple ClientSession instances are required. - * - * The ClientSession needs an io_context to run. The io_context is not owned - * by the ClientSession and must be kept alive by the user, e.g. by a work - * object. - * - * Upon creation, the ClientSession will connect to a server via the given - * address and port. Both synchronous and asynchronous service calls are - * available. The async service callbacks are executed by the io_context - * thread. Therefore, the callbacks must not block the io_context thread for - * too long. - * - * ========================================================================= - * _Important_: Do not stop the io_context while the client session is - * running. This may cause undefined behavior. Instead, call - * stop() and wait for the io_context to run out of work on its - * own. - * - * _Tip_: Use the eCAL::service::ClientManager class to manage the - * client's lifecycle. This enables you to stop all client - * sessions from a single place when performing an application - * shutdown. - * ========================================================================= - * - * Sample conde: - * - * @code{.cpp} - * - * // Create an io_context and a work object to keep it alive - * auto io_context = std::make_shared(); - * asio::io_context::work work(*io_context); - * - * // Creat a thread for the io_context - * std::thread io_context_thread([&io_context]() { io_context->run(); }); - * - * // Create client sessions - * auto client_session = eCAL::service::ClientSession::create(io_context, ...) - * - * // call a service asynchronously - * client_session->async_call_service(...); - * - * // DO STUFF - * - * // Stop the client session - * client_session->stop(); - * - * // Wait for the io_context to run out of work - * io_context_thread.join(); - * - * @endcode - */ - class ClientSession - { - ////////////////////////////////////////////// - // Internal types for better consistency - ////////////////////////////////////////////// - public: - using EventCallbackT = ClientEventCallbackT; - using ResponseCallbackT = ClientResponseCallbackT; - using DeleteCallbackT = std::function; - - ////////////////////////////////////////////// - // Constructor, Destructor, Create - ////////////////////////////////////////////// - public: - /** - * @brief Creates a new ClientSession instance. - * - * A new ClientSession will immediatelly start connecting to a server on - * the given address and port. - * - * ========================================================================= - * _Important_: Do not stop the io_context while the client session is - * running. This may cause undefined behavior. Instead, call - * stop() and wait for the io_context to run out of work on its - * own. - * - * _Tip_: Use the eCAL::service::ClientManager class to manage the - * client's lifecycle. This enables you to stop all client - * sessions from a single place when performing an application - * shutdown. - * ========================================================================= - * - * @param io_context The io_context to use for the session and all callbacks. - * @param protocol_version The protocol version to use for the session. When this is 0, the legacy buggy protocol is used. - * @param server_list A list of endpoints to connect to. Must not be empty. The endpoints will be tried in the given order until a working endpoint is found. - * @param event_callback The callback to be called when the session's state changes, i.e. when the session successfully connected to a server or disconnected from it. - * @param logger The logger to use for logging. - * @param delete_callback The callback to be called when the session is deleted. This is useful for the eCAL::service::ClientManager to keep track of the number of active sessions. - * - * @return The new ClientSession instance as a shared_ptr. - */ - static std::shared_ptr create(const std::shared_ptr& io_context - , std::uint8_t protocol_version - , const std::vector>& server_list - , const EventCallbackT& event_callback - , const LoggerT& logger - , const DeleteCallbackT& delete_callback); - - static std::shared_ptr create(const std::shared_ptr& io_context - , std::uint8_t protocol_version - , const std::vector>& server_list - , const EventCallbackT& event_callback - , const LoggerT& logger = default_logger("Service Client")); - - static std::shared_ptr create(const std::shared_ptr& io_context - , std::uint8_t protocol_version - , const std::vector>& server_list - , const EventCallbackT& event_callback - , const DeleteCallbackT& delete_callback); - - protected: - ClientSession(const std::shared_ptr& io_context - , std::uint8_t protocol_version - , const std::vector>& server_list - , const EventCallbackT& event_callback - , const LoggerT& logger); - - public: - // Delete copy constructor and assignment operator - ClientSession(const ClientSession&) = delete; - ClientSession& operator=(const ClientSession&) = delete; - - // Delete move constructor and assignment operator - ClientSession(ClientSession&&) = delete; - ClientSession& operator=(ClientSession&&) = delete; - - ~ClientSession(); - - ////////////////////////////////////////////// - // Public API - ////////////////////////////////////////////// - public: - /** - * @brief Calls the server asynchronously. - * - * This function will call the server asynchronously. The response_callback - * will be called when the server responds. The response_callback will be - * called from the io_context thread. Therefore, the response_callback must - * not block the io_context thread for too long. - * - * When an error occurs, the response_callback will be called with an error. - * - * When the client has been stopped manually, this function will return - * false. In that case, the response_callback will not be called, as there - * is no way to make sure, that the io_context is still running. - * - * @param request The request to send to the server. - * @param response_callback The callback to be called when the server responds or an error occurs. - * - * @return true if the request was sent enqueued successfully, false otherwise. If this returns false, the response_callback will not be called. - */ - bool async_call_service(const std::shared_ptr& request, const ResponseCallbackT& response_callback); - - /** - * @brief Calls the server synchronously. - * - * This function will call the server synchronously. The function will block - * until the server responds or an error occurs. The response will be - * written to the response parameter - * - * If this function deadlocks, you must check that the io_context is - * running, as that is required for the this function to un-block. The - * io_context must therefore never been stopped. Instead, call stop() and - * wait for the io_context to run out of work on its own. - * - * @param request The request to send to the server. - * @param response The server's response - * - * @return The error that occured or eCAL::service::Error::OK if no error occured. - */ - eCAL::service::Error call_service(const std::shared_ptr& request, std::shared_ptr& response); - - /** - * @brief Get the host that this client is connected to. - * - * Get the host that this client is connected to. - * If the client is not connected, this function will return an empty - * string. Otherwise, it will return the hostname from the list - * server_list that the client is connected to. - * - * The host is not resolved to an IP address. Use get_remote_endpoint() - * to get the actual IP address. - * - * @return The host that this client is connected to. - */ - std::string get_host() const; - - /** - * @brief Get the port that this client session is connected to. - * - * Get the port that this client session is connected to. If the client - * is not connected, this function will return 0. Otherwise, it will - * return the port from the list server_list that the client is connected - * to. - * - * @return The port that this client is connected to - */ - std::uint16_t get_port() const; - - /** - * @brief Get the remote endpoint that this client session is connected to. - * - * Get the remote endpoint that this client session is connected to. Only - * valid, if the client session is actually connected to a server. If a - * hostname was given, this function will return the resolved IP address. - */ - asio::ip::tcp::endpoint get_remote_endpoint() const; - - /** - * @brief Get the state of this client session. - * - * @return the state of this client session. - */ - State get_state() const; - - /** - * @brief Get the accepted protocol version that the server and client have agreed on. - * - * If the connection hasn't been established yet, this function will return 0. - * - * @return The accepted protocol version that the server and client have agreed on. - */ - std::uint8_t get_accepted_protocol_version() const; - - /** - * @brief Get the number of pending requests - * - * @return The number of pending requests - */ - int get_queue_size() const; - - /** - * @brief Stops the client session. - * - * This function will stop the client session. The client session will - * disconnect from the server and will not accept any new requests. Any - * further calls to async_call_service() will fail with an error. - * - * Once the client session has been stopped, it cannot be restarted. You - * must create a new client session instead. - */ - void stop(); - - ////////////////////////////////////////////// - // Member Variables - ////////////////////////////////////////////// - private: - std::shared_ptr impl_; //!< The implementation of the client session - }; - } // namespace service -} // namespace eCAL diff --git a/ecal/service/ecal_service/include/ecal/service/error.h b/ecal/service/ecal_service/include/ecal/service/error.h deleted file mode 100644 index e2ef82d21b..0000000000 --- a/ecal/service/ecal_service/include/ecal/service/error.h +++ /dev/null @@ -1,110 +0,0 @@ -/* ========================= eCAL LICENSE ================================= - * - * Copyright (C) 2016 - 2019 Continental Corporation - * - * 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. - * - * ========================= eCAL LICENSE ================================= -*/ - -#pragma once - -#include - -namespace eCAL -{ - namespace service - { - class Error - { - ////////////////////////////////////////// - // Data model - ////////////////////////////////////////// - public: - enum ErrorCode - { - // Generic - OK, - GENERIC_ERROR, - - // Client Calls - CONNECTION_CLOSED, - UNKNOWN_SERVER, - PROTOCOL_ERROR, - STOPPED_BY_USER, - }; - - ////////////////////////////////////////// - // Constructor & Destructor - ////////////////////////////////////////// - public: - Error(ErrorCode error_code, const std::string& message) : error_code_(error_code), message_(message) {} - Error(ErrorCode error_code) : error_code_(error_code) {} - - ////////////////////////////////////////// - // Public API - ////////////////////////////////////////// - public: - inline std::string GetDescription() const - { - switch (error_code_) - { - // Generic - case OK: return "OK"; break; - case GENERIC_ERROR: return "Error"; break; - - // Client Calls - case CONNECTION_CLOSED: return "Connection closed"; break; - case UNKNOWN_SERVER: return "Unknown server"; break; - case PROTOCOL_ERROR: return "Protocol error"; break; - case STOPPED_BY_USER: return "Stopped by user"; break; - - default: return "Unknown error"; - } - } - - inline std::string ToString() const - { - return (message_.empty() ? GetDescription() : GetDescription() + " (" + message_ + ")"); - } - - const inline std::string& GetMessage() const - { - return message_; - } - - ////////////////////////////////////////// - // Operators - ////////////////////////////////////////// - inline operator bool() const { return error_code_ != ErrorCode::OK; } - inline bool operator== (const Error& other) const { return error_code_ == other.error_code_; } - inline bool operator== (const ErrorCode other) const { return error_code_ == other; } - inline bool operator!= (const Error& other) const { return error_code_ != other.error_code_; } - inline bool operator!= (const ErrorCode other) const { return error_code_ != other; } - - inline Error& operator=(ErrorCode error_code) - { - error_code_ = error_code; - return *this; - } - - ////////////////////////////////////////// - // Member Variables - ////////////////////////////////////////// - private: - ErrorCode error_code_; - std::string message_; - }; - - } // namespace service -} // namespace eCAL diff --git a/ecal/service/ecal_service/include/ecal/service/logger.h b/ecal/service/ecal_service/include/ecal/service/logger.h deleted file mode 100644 index 57c31aa8ad..0000000000 --- a/ecal/service/ecal_service/include/ecal/service/logger.h +++ /dev/null @@ -1,75 +0,0 @@ -/* ========================= eCAL LICENSE ===== ============================ - * - * Copyright (C) 2016 - 2019 Continental Corporation - * - * 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. - * - * ========================= eCAL LICENSE ================================= -*/ - -#pragma once - -#include -#include -#include - -namespace eCAL -{ - namespace service - { - enum class LogLevel - { - DebugVerbose, - Debug, - Info, - Warning, - Error, - Fatal, - }; - - using LoggerT = std::function; - - inline LoggerT default_logger(const std::string& node_name, LogLevel min_log_level = LogLevel::DebugVerbose) - { - return [node_name, min_log_level](const LogLevel log_level, const std::string& message) - { - if (log_level < min_log_level) - return; - - switch (log_level) - { - case LogLevel::DebugVerbose: - std::cout << "[" + node_name + "] [Debug+] " + message + "\n"; - break; - case LogLevel::Debug: - std::cout << "[" + node_name + "] [Debug] " + message + "\n"; - break; - case LogLevel::Info: - std::cout << "[" + node_name + "] [Info] " + message + "\n"; - break; - case LogLevel::Warning: - std::cerr << "[" + node_name + "] [Warning] " + message + "\n"; - break; - case LogLevel::Error: - std::cerr << "[" + node_name + "] [Error] " + message + "\n"; - break; - case LogLevel::Fatal: - std::cerr << "[" + node_name + "] [Fatal] " + message + "\n"; - break; - default: - break; - } - }; - } - } -} \ No newline at end of file diff --git a/ecal/service/ecal_service/include/ecal/service/server.h b/ecal/service/ecal_service/include/ecal/service/server.h deleted file mode 100644 index 8b60d9b51b..0000000000 --- a/ecal/service/ecal_service/include/ecal/service/server.h +++ /dev/null @@ -1,211 +0,0 @@ -/* ========================= eCAL LICENSE ================================= - * - * Copyright (C) 2016 - 2019 Continental Corporation - * - * 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. - * - * ========================= eCAL LICENSE ================================= -*/ - -#pragma once - -#include -#include -#include - -#include - -#include "logger.h" -#include "server_session_types.h" - -namespace eCAL -{ - namespace service - { - // Forward declaration - class ServerImpl; - - /** - * @brief The eCAL::service::Server class represents a binary service server that can be used may multiple clients. - * - * The Server needs an io_context to run. It will listen on a specified - * port. When desired, the server can be opened on port 0, which will the OS - * chose a free port. - * The server uses one callback for the actual service function and another - * callback for events. When stopping, a Disconnect event for each connected - * client will be fired. - * - * Callbacks are executed in the context of the io_context. Therfore, long - * running callbacks can block the server and everything else, that is - * dependent on the io_context. - * - * ========================================================================= - * _Important_: Do not stop the io_context while the server is running. - * This may cause undefined behavior. In fact, the io_context - * should run out of work on its own. - * - * _Tip_: Use the eCAL::service::ServerManager class to manage the - * server's lifecycle. This enables you to stop all servers from - * a single place when performing an application shutdown. - * ========================================================================= - * - * Sample code: - * - * auto io_context = std::make_shared(); - * auto dummy_work = std::make_shared(*io_context); - * - * std::thread io_thread([&io_context]() { io_context->run(); }); - * - * auto server = eCAL::service::Server::create(io_context, ...) - * - * // Do stuff - * - * server->stop(); - * dummy_work->reset(); - * io_thread.join(); - * - */ - class Server - { - ////////////////////////////////////////////// - // Internal types for better consistency - ////////////////////////////////////////////// - public: - using EventCallbackT = ServerEventCallbackT; - using ServiceCallbackT = ServerServiceCallbackT; - using DeleteCallbackT = std::function; - - /////////////////////////////////////////// - // Constructor, Destructor, Create - /////////////////////////////////////////// - - public: - /** - * @brief Creates a new Server instance. - * - * A new server will directly start listening on the specified port and wait for new connections. - * - * ========================================================================= - * _Important_: Do not stop the io_context while the server is running. - * This may cause undefined behavior. In fact, the io_context - * should run out of work on its own. - * - * _Tip_: Use the eCAL::service::ServerManager class to manage the - * server's lifecycle. This enables you to stop all servers from - * a single place when performing an application shutdown. - * ========================================================================= - * - * @param io_context The io_context to use for the server and all callbacks - * @param protocol_version The protocol version to use. When this is 0, the buggy protocol version 0 will be used. - * @param port The port to listen on. When this is 0, the OS will chose a free port. - * @param service_callback The callback to use for service calls. Will be executed in the context of the io_context. - * @param parallel_service_calls_enabled When true, service calls will be executed in parallel. When false, service calls will be executed sequentially. - * @param event_callback The callback to use for events (clients connect or clients disconnect). Will be executed in the context of the io_context. - * @param logger A function used for logging. - * @param delete_callback A callback that will be executed when the server is deleted. - * - * @return The new server instance. - */ - static std::shared_ptr create(const std::shared_ptr& io_context - , std::uint8_t protocol_version - , std::uint16_t port - , const ServiceCallbackT& service_callback - , bool parallel_service_calls_enabled - , const EventCallbackT& event_callback - , const LoggerT& logger - , const DeleteCallbackT& delete_callback); - - static std::shared_ptr create(const std::shared_ptr& io_context - , std::uint8_t protocol_version - , std::uint16_t port - , const ServiceCallbackT& service_callback - , bool parallel_service_calls_enabled - , const EventCallbackT& event_callback - , const LoggerT& logger = default_logger("Service Server")); - - static std::shared_ptr create(const std::shared_ptr& io_context - , std::uint8_t protocol_version - , std::uint16_t port - , const ServiceCallbackT& service_callback - , bool parallel_service_calls_enabled - , const EventCallbackT& event_callback - , const DeleteCallbackT& delete_callback); - protected: - Server(const std::shared_ptr& io_context - , std::uint8_t protocol_version - , std::uint16_t port - , const ServiceCallbackT& service_callback - , bool parallel_service_calls_enabled - , const EventCallbackT& event_callback - , const LoggerT& logger); - - public: - Server(const Server&) = delete; // Copy construct - Server(Server&&) = delete; // Move construct - - Server& operator=(const Server&) = delete; // Copy assign - Server& operator=(Server&&) = delete; // Move assign - - ~Server() = default; - - /////////////////////////////////////////// - // API - /////////////////////////////////////////// - - public: - - /** - * @brief Checks if any client is currently connected to the server. - * - * @return true, when at least one client is connected. False otherwise. - */ - bool is_connected() const; - - /** - * @brief Get the number of currently connected clients. - * - * @return the number of connected clients - */ - int get_connection_count() const; - - /** - * @brief Returns the port the server is listening on. - * - * When the server was created with port 0, this will return the port the - * OS chose. - * - * @return The port - */ - std::uint16_t get_port() const; - - /** - * @brief Stops the server - * - * This closes the socket and stops the server. After the server has been - * stopped, it will still execute disconnect callbacks. The server will - * not accept new connections, though. - * - * A server that has been stopped cannot be restarted. Create a new - * server, when desired. - */ - void stop(); - - /////////////////////////////////////////// - // Member Variables - /////////////////////////////////////////// - private: - std::shared_ptr impl_; //!< The private implementation - }; - - } // namespace service -} // namespace eCAL diff --git a/ecal/service/ecal_service/include/ecal/service/server_manager.h b/ecal/service/ecal_service/include/ecal/service/server_manager.h deleted file mode 100644 index f54c4bb7fa..0000000000 --- a/ecal/service/ecal_service/include/ecal/service/server_manager.h +++ /dev/null @@ -1,191 +0,0 @@ -/* ========================= eCAL LICENSE ================================= - * - * Copyright (C) 2016 - 2019 Continental Corporation - * - * 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. - * - * ========================= eCAL LICENSE ================================= -*/ - -#pragma once - -#include -#include -#include -#include -#include - -#include - -#include - -#include // IWYU pragma: export - -namespace eCAL -{ - namespace service - { - /** - * @brief Manager for eCAL::service::server instances - * - * The ServerManager keeps track of and manages all eCAL::service::server - * instances that it created. It is used to create and stop servers. The - * user doesn't need to manage the servers manually, e.g. for stopping them - * from a central place. - * - * The ServerManager is only available as shared_ptr. It must be created - * using the static create() method. - * - * - Upon creation, the ServerManager will create a work object for the - * given io_context. This will keep the io_context alive, even if there - * are no servers running. - * - * - For creating a server, the create_server() method must be used. This - * will create a new server instance and return a shared_ptr to it. - * - * - For stopping all servers, the stop() method must be used. This - * will stop all servers and delete the internal work object, so the - * thread executing it can be joined. - * - * ========================================================================= - * _Important_: Do not stop the io_context. This may cause undefined - * behavior. Instead, stop the server manager and wait for the - * io_context to run out of work on its own. - * ========================================================================= - * - * Example code: - * - * @code {.cpp} - * - * // Create a server manager - * auto server_manager = eCAL::service::ServerManager::create(io_context); - * - * // Create and start an io_context thread. - * std::thread io_context_thread([&io_context]() { io_context->run(); }); - * - * // Create actual server instances - * auto server1 = server_manager->create_server(...) - * auto server2 = server_manager->create_server(...) - * - * // DO STUFF - * - * // Stop ALL servers from a common place - * server_manager->stop(); - * - * // Join the io_context thread. The io_context does not need to be stopped. - * io_context_thread.join(); - * - * @endcode - */ - class ServerManager : public std::enable_shared_from_this - { - /////////////////////////////////////////////////////// - // Constructor, Destructor, Create - /////////////////////////////////////////////////////// - public: - /** - * @brief Create a new server manager, that can be used to create and stop servers - * - * After creation, the server manager will create a work object for the - * given io_context. This will keep the io_context alive, even if there - * are no servers running. When stopping the servers, that work object - * will be deleted and the io_context will run out of work on its own. - * - * @param io_context The io context, that will be used for all servers - * @param logger A logger-function that will be used for by all servers - * - * @return A shared_ptr to the created server manager - */ - static std::shared_ptr create(const std::shared_ptr& io_context, const LoggerT& logger = default_logger("Service Server")); - - // delete copy and move constructors and assign operators - ServerManager(const ServerManager&) = delete; // Copy construct - ServerManager(ServerManager&&) = delete; // Move construct - ServerManager& operator=(const ServerManager&) = delete; // Copy assign - ServerManager& operator=(ServerManager&&) = delete; // Move assign - - // Constructor, Destructor - protected: - ServerManager(const std::shared_ptr& io_context, const LoggerT& logger); - - public: - ~ServerManager(); - - /////////////////////////////////////////////////////// - // Public API - /////////////////////////////////////////////////////// - - public: - /** - * @brief Create a new server instance, which is managed by this server manager. - * - * The server manager will keep track of the create server internally. The - * server (and all other servers, that have been created by this manager) - * can be stopped via the stop() method. - * - * @param protocol_version The protocol version, that will be used by this server - * @param port The port, that the server will listen on. If 0, the OS will choose a free port. - * @param service_callback The callback, that will be called for each incoming service call. The callback will be executed in the io_context thread. - * @param parallel_service_calls_enabled If true, the server will handle incoming service calls in parallel. If false, the server will handle incoming service calls sequentially. - * @param event_callback The callback, that will be called whenever a client connects or disconnects. The callback will be executed in the io_context thread. - * - * @return a shared pointer to the created server - */ - std::shared_ptr create_server(std::uint8_t protocol_version - , std::uint16_t port - , const Server::ServiceCallbackT& service_callback - , bool parallel_service_calls_enabled - , const Server::EventCallbackT& event_callback); - - /** - * @brief Get the number of servers, that are currently managed by this server manager - * @return The number of servers - */ - size_t server_count() const; - - /** - * @brief Stop all servers that are currently managed by this server manager - * - * This will also delete the internal work object, so the thread executing - * the io_context can be joined. The io context will run out of work on - * its own. - * Obviously, this is only true if no other managers etc. use the io_context. - */ - void stop(); - - /** - * @brief Returns true, if the server manager is stopped - * - * If stopped, the server manager cannot be restarted. Create a new one - * instead. Make sure, that the io_context is executed by a thread again, - * when creating a new server manger. - * - * @return true, if the server_manager is stopped. False otherwise. - */ - bool is_stopped() const; - - /////////////////////////////////////////////////////// - // Member variables - /////////////////////////////////////////////////////// - private: - const std::shared_ptr io_context_; //!< Reference to the asio io_context - const LoggerT logger_; //!< Logger for all servers - - mutable std::mutex server_manager_mutex_; //!< Mutex protecting the entire class - bool stopped_; //!< Flag indicating, if the manager is stopped - std::unique_ptr work_; //!< Work object to keep the io_context alive. Will be deleted, when the manager is stopped. - std::map> sessions_; //!< Map of all servers, that are currently managed by this server manager. The raw_ptr is used as key, because it is unique for each server. The weak_ptr is used to actually access the server object, because the server may already be dead and the raw ptr would be dangling in that case. - }; - - } -} diff --git a/ecal/service/ecal_service/include/ecal_service/client_manager.h b/ecal/service/ecal_service/include/ecal_service/client_manager.h new file mode 100644 index 0000000000..baf5fccd8a --- /dev/null +++ b/ecal/service/ecal_service/include/ecal_service/client_manager.h @@ -0,0 +1,202 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2025 Continental Corporation + * + * 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. + * + * ========================= eCAL LICENSE ================================= +*/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include // IWYU pragma: export + +namespace ecal_service +{ + /** + * @brief Manager for ecal_service::ClientSession instances + * + * The ClientManager is used to create and stop ClientSessions. It keeps + * track of ClientSession instances that it created. The user doesn't need + * to manage the Sessions manually, e.g. for stopping them from a central + * place. + * + * The ClientManager is only available as shared_ptr. It must be created + * using the static create() method. + * + * - Upon creation, the ClientManager will create a work object for the + * given io_context. This will keep the io_context alive, even if there + * are no clients running. + * + * - For creating a client, the create_client() method must be used. This + * will create a new client instance and return a shared_ptr to it. + * + * - For stopping all clients, the stop() method must be used. This + * will stop all clients and delete the internal work object, so the + * thread executing it can be joined. + * + * ========================================================================= + * _Important_: Do not stop the io_context. This may cause undefined behavior. + * Instead, stop the client manager and wait for the io_context + * to run out of work on its own. + * ========================================================================= + * + * Example code: + * + * @code {.cpp} + * + * // Create the io_context + * auto io_context = std::make_shared(); + * + * // Create a thread for the io_context + * std::thread io_context_thread([&io_context]() { io_context->run(); }); + * + * // Create a client manager + * auto client_manager = ecal_service::ClientManager::create(io_context, ...); + * + * // Create actual client instances + * auto client1 = client_manager->create_client(...) + * auto client2 = client_manager->create_client(...) + * + * // DO STUFF + * + * // Stop ALL clients from a common place + * client_manager->stop(); + * + * // Join the io_context thread. The io_context does not need to be stopped. + * io_context_thread.join(); + * + * @endcode + * + */ + class ClientManager : public std::enable_shared_from_this + { + /////////////////////////////////////////////////////// + // Constructor, Destructor, Create + /////////////////////////////////////////////////////// + public: + /** + * @brief Create a new ClientManager instance, that can be used to create and stop ClientSession instances. + * + * After creation, the ClientManager will create a work object for the + * given io_context. This will keep the io_context alive, even if there + * are no clients running. When stopping the clients, that work object + * will be deleted and the io_context will run out of work on its own. + * + * @param io_context The io context, that will be used for all client sessions + * @param logger A logger-function that will be used for by all client sessions + * + * @return A shared_ptr to the newly created ClientManager instance + */ + static std::shared_ptr create(const std::shared_ptr& io_context, const LoggerT& logger = default_logger("Service Client")); + + // delete copy and move constructors and assign operators + ClientManager(const ClientManager&) = delete; // Copy construct + ClientManager(ClientManager&&) = delete; // Move construct + ClientManager& operator=(const ClientManager&) = delete; // Copy assign + ClientManager& operator=(ClientManager&&) = delete; // Move assign + + // Constructor, Destructor + protected: + ClientManager(const std::shared_ptr& io_context, const LoggerT& logger); + + public: + ~ClientManager(); + + /////////////////////////////////////////////////////// + // Public API + /////////////////////////////////////////////////////// + public: + /** + * @brief Create a new ClienSession instance, which is managed by this client manager. + * + * The ClientSession will immediatelly connect to the server through the + * given address and port. The protocol version must match the server, + * especially when version 0 (the legacy buggy protocol) is used. Future + * versions are expected to be compatible to each other. + * + * The Event Callback will be called, when the client has connected to the + * server or disconnected from it. + * + * The new Client Session will be managed by the ClientManager and can be + * stopped from this central place. + * + * @param protocol_version The protocol version to use for the client session. If 0, the legacy buggy protocol will be used. + * @param server_list A list of endpoints to connect to. Must not be empty. The endpoints will be tried in the given order until a working endpoint is found. + * @param event_callback The callback, that will be called, when the client has connected to the server or disconnected from it. The callback will be executed in the io_context thread. + * + * @return A shared_ptr to the newly created ClientSession instance + */ + std::shared_ptr create_client(std::uint8_t protocol_version + , const std::vector>& server_list + , const ClientSession::EventCallbackT& event_callback); + + /** + * @brief Returns the number of managed client sessions + * + * @return The number of managed client sessions + */ + size_t client_count() const; + + /** + * @brief Stops the client manager and all managed client sessions + * + * This will stop all managed client sessions and delete the internal + * work object, so the thread executing the io_context can be joined. + * The io context will run out of work on its own. + * + * Once stopped, the client manager cannot be used anymore. It must be + * deleted and a new one must be created. + * + * Make sure, that the io_context is executed by a thread again, when + * creating a new client manager. + */ + void stop(); + + /** + * @brief Returns true, if the client manager is stopped + * + * If stopped, the client manager cannot be restarted. Create a new one + * instead. Make sure, that the io_context is executed by a thread again, + * when creating a new client manager. + * + * @return true, if the client_manager is stopped. False otherwise. + */ + bool is_stopped() const; + + /////////////////////////////////////////////////////// + // Member variables + /////////////////////////////////////////////////////// + private: + const std::shared_ptr io_context_; //!< Reference to the asio io_context + const LoggerT logger_; //!< Logger for all clients + + mutable std::mutex client_manager_mutex_; //!< Mutex protecting the entire class + bool stopped_; //!< Flag indicating, if the manager is stopped + std::unique_ptr work_; //!< Work object to keep the io_context alive. Will be deleted, when the manager is stopped. + std::map> sessions_; //!< Map of all managed client sessions. The raw_ptr is used as key, because it is unique for each client. The weak_ptr is used to actually access the client object, because the client may already be dead and the raw ptr would be dangling in that case. + }; +} diff --git a/ecal/service/ecal_service/include/ecal_service/client_session.h b/ecal/service/ecal_service/include/ecal_service/client_session.h new file mode 100644 index 0000000000..54aa333360 --- /dev/null +++ b/ecal/service/ecal_service/include/ecal_service/client_session.h @@ -0,0 +1,302 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2025 Continental Corporation + * + * 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. + * + * ========================= eCAL LICENSE ================================= +*/ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4834) +#endif +#include +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include +#include +#include +#include + +namespace ecal_service +{ + // Forward declarations + class ClientSessionBase; + + /** + * @brief The eCAL::sercice::ClientSession class represents the binary service client session. + * + * The ClientSession can connect to exactly one service server. For multiple + * connections, multiple ClientSession instances are required. + * + * The ClientSession needs an io_context to run. The io_context is not owned + * by the ClientSession and must be kept alive by the user, e.g. by a work + * object. + * + * Upon creation, the ClientSession will connect to a server via the given + * address and port. Both synchronous and asynchronous service calls are + * available. The async service callbacks are executed by the io_context + * thread. Therefore, the callbacks must not block the io_context thread for + * too long. + * + * ========================================================================= + * _Important_: Do not stop the io_context while the client session is + * running. This may cause undefined behavior. Instead, call + * stop() and wait for the io_context to run out of work on its + * own. + * + * _Tip_: Use the ecal_service::ClientManager class to manage the + * client's lifecycle. This enables you to stop all client + * sessions from a single place when performing an application + * shutdown. + * ========================================================================= + * + * Sample conde: + * + * @code{.cpp} + * + * // Create an io_context and a work object to keep it alive + * auto io_context = std::make_shared(); + * asio::io_context::work work(*io_context); + * + * // Creat a thread for the io_context + * std::thread io_context_thread([&io_context]() { io_context->run(); }); + * + * // Create client sessions + * auto client_session = ecal_service::ClientSession::create(io_context, ...) + * + * // call a service asynchronously + * client_session->async_call_service(...); + * + * // DO STUFF + * + * // Stop the client session + * client_session->stop(); + * + * // Wait for the io_context to run out of work + * io_context_thread.join(); + * + * @endcode + */ + class ClientSession + { + ////////////////////////////////////////////// + // Internal types for better consistency + ////////////////////////////////////////////// + public: + using EventCallbackT = ClientEventCallbackT; + using ResponseCallbackT = ClientResponseCallbackT; + using DeleteCallbackT = std::function; + + ////////////////////////////////////////////// + // Constructor, Destructor, Create + ////////////////////////////////////////////// + public: + /** + * @brief Creates a new ClientSession instance. + * + * A new ClientSession will immediatelly start connecting to a server on + * the given address and port. + * + * ========================================================================= + * _Important_: Do not stop the io_context while the client session is + * running. This may cause undefined behavior. Instead, call + * stop() and wait for the io_context to run out of work on its + * own. + * + * _Tip_: Use the ecal_service::ClientManager class to manage the + * client's lifecycle. This enables you to stop all client + * sessions from a single place when performing an application + * shutdown. + * ========================================================================= + * + * @param io_context The io_context to use for the session and all callbacks. + * @param protocol_version The protocol version to use for the session. When this is 0, the legacy buggy protocol is used. + * @param server_list A list of endpoints to connect to. Must not be empty. The endpoints will be tried in the given order until a working endpoint is found. + * @param event_callback The callback to be called when the session's state changes, i.e. when the session successfully connected to a server or disconnected from it. + * @param logger The logger to use for logging. + * @param delete_callback The callback to be called when the session is deleted. This is useful for the ecal_service::ClientManager to keep track of the number of active sessions. + * + * @return The new ClientSession instance as a shared_ptr. + */ + static std::shared_ptr create(const std::shared_ptr& io_context + , std::uint8_t protocol_version + , const std::vector>& server_list + , const EventCallbackT& event_callback + , const LoggerT& logger + , const DeleteCallbackT& delete_callback); + + static std::shared_ptr create(const std::shared_ptr& io_context + , std::uint8_t protocol_version + , const std::vector>& server_list + , const EventCallbackT& event_callback + , const LoggerT& logger = default_logger("Service Client")); + + static std::shared_ptr create(const std::shared_ptr& io_context + , std::uint8_t protocol_version + , const std::vector>& server_list + , const EventCallbackT& event_callback + , const DeleteCallbackT& delete_callback); + + protected: + ClientSession(const std::shared_ptr& io_context + , std::uint8_t protocol_version + , const std::vector>& server_list + , const EventCallbackT& event_callback + , const LoggerT& logger); + + public: + // Delete copy constructor and assignment operator + ClientSession(const ClientSession&) = delete; + ClientSession& operator=(const ClientSession&) = delete; + + // Delete move constructor and assignment operator + ClientSession(ClientSession&&) = delete; + ClientSession& operator=(ClientSession&&) = delete; + + ~ClientSession(); + + ////////////////////////////////////////////// + // Public API + ////////////////////////////////////////////// + public: + /** + * @brief Calls the server asynchronously. + * + * This function will call the server asynchronously. The response_callback + * will be called when the server responds. The response_callback will be + * called from the io_context thread. Therefore, the response_callback must + * not block the io_context thread for too long. + * + * When an error occurs, the response_callback will be called with an error. + * + * When the client has been stopped manually, this function will return + * false. In that case, the response_callback will not be called, as there + * is no way to make sure, that the io_context is still running. + * + * @param request The request to send to the server. + * @param response_callback The callback to be called when the server responds or an error occurs. + * + * @return true if the request was sent enqueued successfully, false otherwise. If this returns false, the response_callback will not be called. + */ + bool async_call_service(const std::shared_ptr& request, const ResponseCallbackT& response_callback); + + /** + * @brief Calls the server synchronously. + * + * This function will call the server synchronously. The function will block + * until the server responds or an error occurs. The response will be + * written to the response parameter + * + * If this function deadlocks, you must check that the io_context is + * running, as that is required for the this function to un-block. The + * io_context must therefore never been stopped. Instead, call stop() and + * wait for the io_context to run out of work on its own. + * + * @param request The request to send to the server. + * @param response The server's response + * + * @return The error that occured or ecal_service::Error::OK if no error occured. + */ + ecal_service::Error call_service(const std::shared_ptr& request, std::shared_ptr& response); + + /** + * @brief Get the host that this client is connected to. + * + * Get the host that this client is connected to. + * If the client is not connected, this function will return an empty + * string. Otherwise, it will return the hostname from the list + * server_list that the client is connected to. + * + * The host is not resolved to an IP address. Use get_remote_endpoint() + * to get the actual IP address. + * + * @return The host that this client is connected to. + */ + std::string get_host() const; + + /** + * @brief Get the port that this client session is connected to. + * + * Get the port that this client session is connected to. If the client + * is not connected, this function will return 0. Otherwise, it will + * return the port from the list server_list that the client is connected + * to. + * + * @return The port that this client is connected to + */ + std::uint16_t get_port() const; + + /** + * @brief Get the remote endpoint that this client session is connected to. + * + * Get the remote endpoint that this client session is connected to. Only + * valid, if the client session is actually connected to a server. If a + * hostname was given, this function will return the resolved IP address. + */ + asio::ip::tcp::endpoint get_remote_endpoint() const; + + /** + * @brief Get the state of this client session. + * + * @return the state of this client session. + */ + State get_state() const; + + /** + * @brief Get the accepted protocol version that the server and client have agreed on. + * + * If the connection hasn't been established yet, this function will return 0. + * + * @return The accepted protocol version that the server and client have agreed on. + */ + std::uint8_t get_accepted_protocol_version() const; + + /** + * @brief Get the number of pending requests + * + * @return The number of pending requests + */ + int get_queue_size() const; + + /** + * @brief Stops the client session. + * + * This function will stop the client session. The client session will + * disconnect from the server and will not accept any new requests. Any + * further calls to async_call_service() will fail with an error. + * + * Once the client session has been stopped, it cannot be restarted. You + * must create a new client session instead. + */ + void stop(); + + ////////////////////////////////////////////// + // Member Variables + ////////////////////////////////////////////// + private: + std::shared_ptr impl_; //!< The implementation of the client session + }; +} // namespace ecal_service diff --git a/ecal/service/ecal_service/include/ecal/service/client_session_types.h b/ecal/service/ecal_service/include/ecal_service/client_session_types.h similarity index 64% rename from ecal/service/ecal_service/include/ecal/service/client_session_types.h rename to ecal/service/ecal_service/include/ecal_service/client_session_types.h index 113c2593c6..bc57159a07 100644 --- a/ecal/service/ecal_service/include/ecal/service/client_session_types.h +++ b/ecal/service/ecal_service/include/ecal_service/client_session_types.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,19 +23,16 @@ #include #include -#include +#include -namespace eCAL +namespace ecal_service { - namespace service + enum class ClientEventType: int { - enum class ClientEventType: int - { - Connected, - Disconnected, - }; - - using ClientEventCallbackT = std::function; - using ClientResponseCallbackT = std::function&)>; - } // namespace service + Connected, + Disconnected, + }; + + using ClientEventCallbackT = std::function; + using ClientResponseCallbackT = std::function&)>; } // namespace eCAL diff --git a/ecal/service/ecal_service/include/ecal_service/error.h b/ecal/service/ecal_service/include/ecal_service/error.h new file mode 100644 index 0000000000..07ac6247f1 --- /dev/null +++ b/ecal/service/ecal_service/include/ecal_service/error.h @@ -0,0 +1,107 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2025 Continental Corporation + * + * 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. + * + * ========================= eCAL LICENSE ================================= +*/ + +#pragma once + +#include + +namespace ecal_service +{ + class Error + { + ////////////////////////////////////////// + // Data model + ////////////////////////////////////////// + public: + enum ErrorCode + { + // Generic + OK, + GENERIC_ERROR, + + // Client Calls + CONNECTION_CLOSED, + UNKNOWN_SERVER, + PROTOCOL_ERROR, + STOPPED_BY_USER, + }; + + ////////////////////////////////////////// + // Constructor & Destructor + ////////////////////////////////////////// + public: + Error(ErrorCode error_code, const std::string& message) : error_code_(error_code), message_(message) {} + Error(ErrorCode error_code) : error_code_(error_code) {} + + ////////////////////////////////////////// + // Public API + ////////////////////////////////////////// + public: + inline std::string GetDescription() const + { + switch (error_code_) + { + // Generic + case OK: return "OK"; break; + case GENERIC_ERROR: return "Error"; break; + + // Client Calls + case CONNECTION_CLOSED: return "Connection closed"; break; + case UNKNOWN_SERVER: return "Unknown server"; break; + case PROTOCOL_ERROR: return "Protocol error"; break; + case STOPPED_BY_USER: return "Stopped by user"; break; + + default: return "Unknown error"; + } + } + + inline std::string ToString() const + { + return (message_.empty() ? GetDescription() : GetDescription() + " (" + message_ + ")"); + } + + const inline std::string& GetMessage() const + { + return message_; + } + + ////////////////////////////////////////// + // Operators + ////////////////////////////////////////// + inline operator bool() const { return error_code_ != ErrorCode::OK; } + inline bool operator== (const Error& other) const { return error_code_ == other.error_code_; } + inline bool operator== (const ErrorCode other) const { return error_code_ == other; } + inline bool operator!= (const Error& other) const { return error_code_ != other.error_code_; } + inline bool operator!= (const ErrorCode other) const { return error_code_ != other; } + + inline Error& operator=(ErrorCode error_code) + { + error_code_ = error_code; + return *this; + } + + ////////////////////////////////////////// + // Member Variables + ////////////////////////////////////////// + private: + ErrorCode error_code_; + std::string message_; + }; + +} // namespace ecal_service diff --git a/ecal/service/ecal_service/include/ecal_service/logger.h b/ecal/service/ecal_service/include/ecal_service/logger.h new file mode 100644 index 0000000000..823ccb8da3 --- /dev/null +++ b/ecal/service/ecal_service/include/ecal_service/logger.h @@ -0,0 +1,72 @@ +/* ========================= eCAL LICENSE ===== ============================ + * + * Copyright (C) 2016 - 2025 Continental Corporation + * + * 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. + * + * ========================= eCAL LICENSE ================================= +*/ + +#pragma once + +#include +#include +#include + +namespace ecal_service +{ + enum class LogLevel + { + DebugVerbose, + Debug, + Info, + Warning, + Error, + Fatal, + }; + + using LoggerT = std::function; + + inline LoggerT default_logger(const std::string& node_name, LogLevel min_log_level = LogLevel::DebugVerbose) + { + return [node_name, min_log_level](const LogLevel log_level, const std::string& message) + { + if (log_level < min_log_level) + return; + + switch (log_level) + { + case LogLevel::DebugVerbose: + std::cout << "[" + node_name + "] [Debug+] " + message + "\n"; + break; + case LogLevel::Debug: + std::cout << "[" + node_name + "] [Debug] " + message + "\n"; + break; + case LogLevel::Info: + std::cout << "[" + node_name + "] [Info] " + message + "\n"; + break; + case LogLevel::Warning: + std::cerr << "[" + node_name + "] [Warning] " + message + "\n"; + break; + case LogLevel::Error: + std::cerr << "[" + node_name + "] [Error] " + message + "\n"; + break; + case LogLevel::Fatal: + std::cerr << "[" + node_name + "] [Fatal] " + message + "\n"; + break; + default: + break; + } + }; + } +} \ No newline at end of file diff --git a/ecal/service/ecal_service/include/ecal_service/server.h b/ecal/service/ecal_service/include/ecal_service/server.h new file mode 100644 index 0000000000..93df25b79c --- /dev/null +++ b/ecal/service/ecal_service/include/ecal_service/server.h @@ -0,0 +1,208 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2025 Continental Corporation + * + * 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. + * + * ========================= eCAL LICENSE ================================= +*/ + +#pragma once + +#include +#include +#include + +#include + +#include "logger.h" +#include "server_session_types.h" + +namespace ecal_service +{ + // Forward declaration + class ServerImpl; + + /** + * @brief The ecal_service::Server class represents a binary service server that can be used may multiple clients. + * + * The Server needs an io_context to run. It will listen on a specified + * port. When desired, the server can be opened on port 0, which will the OS + * chose a free port. + * The server uses one callback for the actual service function and another + * callback for events. When stopping, a Disconnect event for each connected + * client will be fired. + * + * Callbacks are executed in the context of the io_context. Therfore, long + * running callbacks can block the server and everything else, that is + * dependent on the io_context. + * + * ========================================================================= + * _Important_: Do not stop the io_context while the server is running. + * This may cause undefined behavior. In fact, the io_context + * should run out of work on its own. + * + * _Tip_: Use the ecal_service::ServerManager class to manage the + * server's lifecycle. This enables you to stop all servers from + * a single place when performing an application shutdown. + * ========================================================================= + * + * Sample code: + * + * auto io_context = std::make_shared(); + * auto dummy_work = std::make_shared(*io_context); + * + * std::thread io_thread([&io_context]() { io_context->run(); }); + * + * auto server = ecal_service::Server::create(io_context, ...) + * + * // Do stuff + * + * server->stop(); + * dummy_work->reset(); + * io_thread.join(); + * + */ + class Server + { + ////////////////////////////////////////////// + // Internal types for better consistency + ////////////////////////////////////////////// + public: + using EventCallbackT = ServerEventCallbackT; + using ServiceCallbackT = ServerServiceCallbackT; + using DeleteCallbackT = std::function; + + /////////////////////////////////////////// + // Constructor, Destructor, Create + /////////////////////////////////////////// + + public: + /** + * @brief Creates a new Server instance. + * + * A new server will directly start listening on the specified port and wait for new connections. + * + * ========================================================================= + * _Important_: Do not stop the io_context while the server is running. + * This may cause undefined behavior. In fact, the io_context + * should run out of work on its own. + * + * _Tip_: Use the ecal_service::ServerManager class to manage the + * server's lifecycle. This enables you to stop all servers from + * a single place when performing an application shutdown. + * ========================================================================= + * + * @param io_context The io_context to use for the server and all callbacks + * @param protocol_version The protocol version to use. When this is 0, the buggy protocol version 0 will be used. + * @param port The port to listen on. When this is 0, the OS will chose a free port. + * @param service_callback The callback to use for service calls. Will be executed in the context of the io_context. + * @param parallel_service_calls_enabled When true, service calls will be executed in parallel. When false, service calls will be executed sequentially. + * @param event_callback The callback to use for events (clients connect or clients disconnect). Will be executed in the context of the io_context. + * @param logger A function used for logging. + * @param delete_callback A callback that will be executed when the server is deleted. + * + * @return The new server instance. + */ + static std::shared_ptr create(const std::shared_ptr& io_context + , std::uint8_t protocol_version + , std::uint16_t port + , const ServiceCallbackT& service_callback + , bool parallel_service_calls_enabled + , const EventCallbackT& event_callback + , const LoggerT& logger + , const DeleteCallbackT& delete_callback); + + static std::shared_ptr create(const std::shared_ptr& io_context + , std::uint8_t protocol_version + , std::uint16_t port + , const ServiceCallbackT& service_callback + , bool parallel_service_calls_enabled + , const EventCallbackT& event_callback + , const LoggerT& logger = default_logger("Service Server")); + + static std::shared_ptr create(const std::shared_ptr& io_context + , std::uint8_t protocol_version + , std::uint16_t port + , const ServiceCallbackT& service_callback + , bool parallel_service_calls_enabled + , const EventCallbackT& event_callback + , const DeleteCallbackT& delete_callback); + protected: + Server(const std::shared_ptr& io_context + , std::uint8_t protocol_version + , std::uint16_t port + , const ServiceCallbackT& service_callback + , bool parallel_service_calls_enabled + , const EventCallbackT& event_callback + , const LoggerT& logger); + + public: + Server(const Server&) = delete; // Copy construct + Server(Server&&) = delete; // Move construct + + Server& operator=(const Server&) = delete; // Copy assign + Server& operator=(Server&&) = delete; // Move assign + + ~Server() = default; + + /////////////////////////////////////////// + // API + /////////////////////////////////////////// + + public: + + /** + * @brief Checks if any client is currently connected to the server. + * + * @return true, when at least one client is connected. False otherwise. + */ + bool is_connected() const; + + /** + * @brief Get the number of currently connected clients. + * + * @return the number of connected clients + */ + int get_connection_count() const; + + /** + * @brief Returns the port the server is listening on. + * + * When the server was created with port 0, this will return the port the + * OS chose. + * + * @return The port + */ + std::uint16_t get_port() const; + + /** + * @brief Stops the server + * + * This closes the socket and stops the server. After the server has been + * stopped, it will still execute disconnect callbacks. The server will + * not accept new connections, though. + * + * A server that has been stopped cannot be restarted. Create a new + * server, when desired. + */ + void stop(); + + /////////////////////////////////////////// + // Member Variables + /////////////////////////////////////////// + private: + std::shared_ptr impl_; //!< The private implementation + }; + +} // namespace ecal_service diff --git a/ecal/service/ecal_service/include/ecal_service/server_manager.h b/ecal/service/ecal_service/include/ecal_service/server_manager.h new file mode 100644 index 0000000000..dd1af9144d --- /dev/null +++ b/ecal/service/ecal_service/include/ecal_service/server_manager.h @@ -0,0 +1,188 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2025 Continental Corporation + * + * 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. + * + * ========================= eCAL LICENSE ================================= +*/ + +#pragma once + +#include +#include +#include +#include +#include + +#include + +#include + +#include // IWYU pragma: export + +namespace ecal_service +{ + /** + * @brief Manager for ecal_service::server instances + * + * The ServerManager keeps track of and manages all ecal_service::server + * instances that it created. It is used to create and stop servers. The + * user doesn't need to manage the servers manually, e.g. for stopping them + * from a central place. + * + * The ServerManager is only available as shared_ptr. It must be created + * using the static create() method. + * + * - Upon creation, the ServerManager will create a work object for the + * given io_context. This will keep the io_context alive, even if there + * are no servers running. + * + * - For creating a server, the create_server() method must be used. This + * will create a new server instance and return a shared_ptr to it. + * + * - For stopping all servers, the stop() method must be used. This + * will stop all servers and delete the internal work object, so the + * thread executing it can be joined. + * + * ========================================================================= + * _Important_: Do not stop the io_context. This may cause undefined + * behavior. Instead, stop the server manager and wait for the + * io_context to run out of work on its own. + * ========================================================================= + * + * Example code: + * + * @code {.cpp} + * + * // Create a server manager + * auto server_manager = ecal_service::ServerManager::create(io_context); + * + * // Create and start an io_context thread. + * std::thread io_context_thread([&io_context]() { io_context->run(); }); + * + * // Create actual server instances + * auto server1 = server_manager->create_server(...) + * auto server2 = server_manager->create_server(...) + * + * // DO STUFF + * + * // Stop ALL servers from a common place + * server_manager->stop(); + * + * // Join the io_context thread. The io_context does not need to be stopped. + * io_context_thread.join(); + * + * @endcode + */ + class ServerManager : public std::enable_shared_from_this + { + /////////////////////////////////////////////////////// + // Constructor, Destructor, Create + /////////////////////////////////////////////////////// + public: + /** + * @brief Create a new server manager, that can be used to create and stop servers + * + * After creation, the server manager will create a work object for the + * given io_context. This will keep the io_context alive, even if there + * are no servers running. When stopping the servers, that work object + * will be deleted and the io_context will run out of work on its own. + * + * @param io_context The io context, that will be used for all servers + * @param logger A logger-function that will be used for by all servers + * + * @return A shared_ptr to the created server manager + */ + static std::shared_ptr create(const std::shared_ptr& io_context, const LoggerT& logger = default_logger("Service Server")); + + // delete copy and move constructors and assign operators + ServerManager(const ServerManager&) = delete; // Copy construct + ServerManager(ServerManager&&) = delete; // Move construct + ServerManager& operator=(const ServerManager&) = delete; // Copy assign + ServerManager& operator=(ServerManager&&) = delete; // Move assign + + // Constructor, Destructor + protected: + ServerManager(const std::shared_ptr& io_context, const LoggerT& logger); + + public: + ~ServerManager(); + + /////////////////////////////////////////////////////// + // Public API + /////////////////////////////////////////////////////// + + public: + /** + * @brief Create a new server instance, which is managed by this server manager. + * + * The server manager will keep track of the create server internally. The + * server (and all other servers, that have been created by this manager) + * can be stopped via the stop() method. + * + * @param protocol_version The protocol version, that will be used by this server + * @param port The port, that the server will listen on. If 0, the OS will choose a free port. + * @param service_callback The callback, that will be called for each incoming service call. The callback will be executed in the io_context thread. + * @param parallel_service_calls_enabled If true, the server will handle incoming service calls in parallel. If false, the server will handle incoming service calls sequentially. + * @param event_callback The callback, that will be called whenever a client connects or disconnects. The callback will be executed in the io_context thread. + * + * @return a shared pointer to the created server + */ + std::shared_ptr create_server(std::uint8_t protocol_version + , std::uint16_t port + , const Server::ServiceCallbackT& service_callback + , bool parallel_service_calls_enabled + , const Server::EventCallbackT& event_callback); + + /** + * @brief Get the number of servers, that are currently managed by this server manager + * @return The number of servers + */ + size_t server_count() const; + + /** + * @brief Stop all servers that are currently managed by this server manager + * + * This will also delete the internal work object, so the thread executing + * the io_context can be joined. The io context will run out of work on + * its own. + * Obviously, this is only true if no other managers etc. use the io_context. + */ + void stop(); + + /** + * @brief Returns true, if the server manager is stopped + * + * If stopped, the server manager cannot be restarted. Create a new one + * instead. Make sure, that the io_context is executed by a thread again, + * when creating a new server manger. + * + * @return true, if the server_manager is stopped. False otherwise. + */ + bool is_stopped() const; + + /////////////////////////////////////////////////////// + // Member variables + /////////////////////////////////////////////////////// + private: + const std::shared_ptr io_context_; //!< Reference to the asio io_context + const LoggerT logger_; //!< Logger for all servers + + mutable std::mutex server_manager_mutex_; //!< Mutex protecting the entire class + bool stopped_; //!< Flag indicating, if the manager is stopped + std::unique_ptr work_; //!< Work object to keep the io_context alive. Will be deleted, when the manager is stopped. + std::map> sessions_; //!< Map of all servers, that are currently managed by this server manager. The raw_ptr is used as key, because it is unique for each server. The weak_ptr is used to actually access the server object, because the server may already be dead and the raw ptr would be dangling in that case. + }; + +} diff --git a/ecal/service/ecal_service/include/ecal/service/server_session_types.h b/ecal/service/ecal_service/include/ecal_service/server_session_types.h similarity index 57% rename from ecal/service/ecal_service/include/ecal/service/server_session_types.h rename to ecal/service/ecal_service/include/ecal_service/server_session_types.h index fffc828a35..ed89202c5b 100644 --- a/ecal/service/ecal_service/include/ecal/service/server_session_types.h +++ b/ecal/service/ecal_service/include/ecal_service/server_session_types.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,17 +23,14 @@ #include #include -namespace eCAL +namespace ecal_service { - namespace service + enum class ServerEventType: int { - enum class ServerEventType: int - { - Connected, //!< A client has connected successfully. - Disconnected, //!< The connection to a client has been closed for any reason. - }; + Connected, //!< A client has connected successfully. + Disconnected, //!< The connection to a client has been closed for any reason. + }; - using ServerServiceCallbackT = std::function& request, const std::shared_ptr& response)>; - using ServerEventCallbackT = std::function; - } // namespace service -} // namespace eCAL + using ServerServiceCallbackT = std::function& request, const std::shared_ptr& response)>; + using ServerEventCallbackT = std::function; +} // namespace ecal_service diff --git a/ecal/service/ecal_service/include/ecal/service/state.h b/ecal/service/ecal_service/include/ecal_service/state.h similarity index 64% rename from ecal/service/ecal_service/include/ecal/service/state.h rename to ecal/service/ecal_service/include/ecal_service/state.h index aec91a374a..f256760156 100644 --- a/ecal/service/ecal_service/include/ecal/service/state.h +++ b/ecal/service/ecal_service/include/ecal_service/state.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,16 +19,13 @@ #pragma once -namespace eCAL +namespace ecal_service { - namespace service + enum class State { - enum class State - { - NOT_CONNECTED, //!< Initial state - HANDSHAKE, //!< The connection is currently in handshake state. - CONNECTED, //!< The connection is established and ready to exchange data. - FAILED, //!< The connection has been closed due to an error or by the user - }; - } + NOT_CONNECTED, //!< Initial state + HANDSHAKE, //!< The connection is currently in handshake state. + CONNECTED, //!< The connection is established and ready to exchange data. + FAILED, //!< The connection has been closed due to an error or by the user + }; } diff --git a/ecal/service/ecal_service/src/client_manager.cpp b/ecal/service/ecal_service/src/client_manager.cpp index 57431782a1..c4c749032d 100644 --- a/ecal/service/ecal_service/src/client_manager.cpp +++ b/ecal/service/ecal_service/src/client_manager.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ * ========================= eCAL LICENSE ================================= */ -#include +#include #include #include @@ -28,95 +28,91 @@ #include -#include -#include +#include +#include #include #include -namespace eCAL +namespace ecal_service { - namespace service + /////////////////////////////////////////////////////// + // Constructor, Destructor, Create + /////////////////////////////////////////////////////// + std::shared_ptr ClientManager::create(const std::shared_ptr& io_context, const LoggerT& logger) { - /////////////////////////////////////////////////////// - // Constructor, Destructor, Create - /////////////////////////////////////////////////////// - std::shared_ptr ClientManager::create(const std::shared_ptr& io_context, const LoggerT& logger) - { - return std::shared_ptr(new ClientManager(io_context, logger)); - } + return std::shared_ptr(new ClientManager(io_context, logger)); + } - ClientManager::ClientManager(const std::shared_ptr& io_context, const LoggerT& logger) - : io_context_(io_context) - , logger_(logger) - , stopped_(false) - , work_(std::make_unique(*io_context)) - {} + ClientManager::ClientManager(const std::shared_ptr& io_context, const LoggerT& logger) + : io_context_(io_context) + , logger_(logger) + , stopped_(false) + , work_(std::make_unique(*io_context)) + {} - ClientManager::~ClientManager() + ClientManager::~ClientManager() + { + stop(); + } + + /////////////////////////////////////////////////////// + // Public API + /////////////////////////////////////////////////////// + std::shared_ptr ClientManager::create_client(std::uint8_t protocol_version + , const std::vector>& server_list + , const ClientSession::EventCallbackT& event_callback) + { + const std::lock_guard lock(client_manager_mutex_); + if (stopped_) { - stop(); + return nullptr; } - /////////////////////////////////////////////////////// - // Public API - /////////////////////////////////////////////////////// - std::shared_ptr ClientManager::create_client(std::uint8_t protocol_version - , const std::vector>& server_list - , const ClientSession::EventCallbackT& event_callback) + auto deleter = [weak_me = std::weak_ptr(shared_from_this())](ClientSession* session) { - const std::lock_guard lock(client_manager_mutex_); - if (stopped_) + auto me = weak_me.lock(); + if (me) { - return nullptr; + // Remove the session from the sessions_ map + const std::lock_guard lock(me->client_manager_mutex_); + me->sessions_.erase(session); } + }; - auto deleter = [weak_me = std::weak_ptr(shared_from_this())](ClientSession* session) - { - auto me = weak_me.lock(); - if (me) - { - // Remove the session from the sessions_ map - const std::lock_guard lock(me->client_manager_mutex_); - me->sessions_.erase(session); - } - }; + auto client = ClientSession::create(io_context_, protocol_version, server_list, event_callback, logger_, deleter); + sessions_.emplace(client.get(), client); + return client; + } - auto client = ClientSession::create(io_context_, protocol_version, server_list, event_callback, logger_, deleter); - sessions_.emplace(client.get(), client); - return client; - } + size_t ClientManager::client_count() const + { + const std::lock_guard lock(client_manager_mutex_); + return sessions_.size(); + } - size_t ClientManager::client_count() const + void ClientManager::stop() + { + std::map> sessions_copy; { const std::lock_guard lock(client_manager_mutex_); - return sessions_.size(); + stopped_ = true; + sessions_copy = sessions_; } - void ClientManager::stop() + // stop all clients without having the mutex locked, so we don't crash, when this thread directly calls the delete callback, that itself needs to have the mutex locked. + for (auto& server_weak : sessions_copy) { - std::map> sessions_copy; - { - const std::lock_guard lock(client_manager_mutex_); - stopped_ = true; - sessions_copy = sessions_; - } - - // stop all clients without having the mutex locked, so we don't crash, when this thread directly calls the delete callback, that itself needs to have the mutex locked. - for (auto& server_weak : sessions_copy) - { - auto server = server_weak.second.lock(); - if (server) - server->stop(); - } - - work_.reset(); + auto server = server_weak.second.lock(); + if (server) + server->stop(); } - bool ClientManager::is_stopped() const - { - const std::lock_guard lock(client_manager_mutex_); - return stopped_; - } + work_.reset(); + } + bool ClientManager::is_stopped() const + { + const std::lock_guard lock(client_manager_mutex_); + return stopped_; } } diff --git a/ecal/service/ecal_service/src/client_session.cpp b/ecal/service/ecal_service/src/client_session.cpp index 83329848d9..08f07d600a 100644 --- a/ecal/service/ecal_service/src/client_session.cpp +++ b/ecal/service/ecal_service/src/client_session.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2024 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ */ #include -#include +#include #include #include @@ -29,122 +29,119 @@ #include -#include -#include -#include +#include +#include +#include #include "client_session_impl_v1.h" #include "condition_variable_signaler.h" -namespace eCAL +namespace ecal_service { - namespace service + std::shared_ptr ClientSession::create(const std::shared_ptr& io_context + , std::uint8_t protocol_version + , const std::vector>& server_list + , const EventCallbackT& event_callback + , const LoggerT& logger + , const DeleteCallbackT& delete_callback) { - std::shared_ptr ClientSession::create(const std::shared_ptr& io_context - , std::uint8_t protocol_version - , const std::vector>& server_list - , const EventCallbackT& event_callback - , const LoggerT& logger - , const DeleteCallbackT& delete_callback) + auto deleter = [delete_callback](ClientSession* session) { - auto deleter = [delete_callback](ClientSession* session) - { - delete_callback(session); - delete session; // NOLINT(cppcoreguidelines-owning-memory) - }; - - return std::shared_ptr(new ClientSession(io_context, protocol_version, server_list, event_callback, logger), deleter); - } + delete_callback(session); + delete session; // NOLINT(cppcoreguidelines-owning-memory) + }; + + return std::shared_ptr(new ClientSession(io_context, protocol_version, server_list, event_callback, logger), deleter); + } + + std::shared_ptr ClientSession::create(const std::shared_ptr& io_context + , std::uint8_t protocol_version + , const std::vector>& server_list + , const EventCallbackT& event_callback + , const LoggerT& logger) + { + return std::shared_ptr(new ClientSession(io_context, protocol_version, server_list, event_callback, logger)); + } + + std::shared_ptr ClientSession::create(const std::shared_ptr& io_context + , std::uint8_t protocol_version + , const std::vector>& server_list + , const EventCallbackT& event_callback + , const DeleteCallbackT& delete_callback) + { + return ClientSession::create(io_context, protocol_version, server_list, event_callback, default_logger("Service Client"), delete_callback); + } + + ClientSession::ClientSession(const std::shared_ptr& io_context + , std::uint8_t /*protocol_version*/ + , const std::vector>& server_list + , const EventCallbackT& event_callback + , const LoggerT& logger) + { + // we support v1 protocol only + impl_ = ClientSessionV1::create(io_context, server_list, event_callback, logger); + } - std::shared_ptr ClientSession::create(const std::shared_ptr& io_context - , std::uint8_t protocol_version - , const std::vector>& server_list - , const EventCallbackT& event_callback - , const LoggerT& logger) - { - return std::shared_ptr(new ClientSession(io_context, protocol_version, server_list, event_callback, logger)); - } + ClientSession::~ClientSession() + { + impl_->stop(); + } - std::shared_ptr ClientSession::create(const std::shared_ptr& io_context - , std::uint8_t protocol_version - , const std::vector>& server_list - , const EventCallbackT& event_callback - , const DeleteCallbackT& delete_callback) - { - return ClientSession::create(io_context, protocol_version, server_list, event_callback, default_logger("Service Client"), delete_callback); - } + ////////////////////////////////////////////// + // Public API + ////////////////////////////////////////////// + bool ClientSession::async_call_service(const std::shared_ptr& request, const ResponseCallbackT& response_callback) + { + return impl_->async_call_service(request, response_callback); + } - ClientSession::ClientSession(const std::shared_ptr& io_context - , std::uint8_t /*protocol_version*/ - , const std::vector>& server_list - , const EventCallbackT& event_callback - , const LoggerT& logger) - { - // we support v1 protocol only - impl_ = ClientSessionV1::create(io_context, server_list, event_callback, logger); - } + ecal_service::Error ClientSession::call_service(const std::shared_ptr& request, std::shared_ptr& response) + { + ecal_service::Error error(Error::GENERIC_ERROR); + + // Create a condition variable and a mutex to wait for the response + std::mutex mutex; + std::condition_variable condition_variable; + bool is_signaled = false; + + bool async_call_successful(false); - ClientSession::~ClientSession() { - impl_->stop(); + // Create a response callback, that will set the response and notify the condition variable + const ResponseCallbackT response_callback + = [&error, &response, signaler = std::make_shared(condition_variable, mutex, is_signaled)] + (const ecal_service::Error& response_error, const std::shared_ptr& response_) + { + response = response_; + error = response_error; + }; + async_call_successful = async_call_service(request, response_callback); } - ////////////////////////////////////////////// - // Public API - ////////////////////////////////////////////// - bool ClientSession::async_call_service(const std::shared_ptr& request, const ResponseCallbackT& response_callback) + if(async_call_successful) { - return impl_->async_call_service(request, response_callback); + // Lock mutex, call service asynchronously and wait for the condition variable to be notified + std::unique_lock lock(mutex); + condition_variable.wait(lock, [&is_signaled]() { return is_signaled; }); + return error; } - - eCAL::service::Error ClientSession::call_service(const std::shared_ptr& request, std::shared_ptr& response) + else { - eCAL::service::Error error(Error::GENERIC_ERROR); - - // Create a condition variable and a mutex to wait for the response - std::mutex mutex; - std::condition_variable condition_variable; - bool is_signaled = false; - - bool async_call_successful(false); - - { - // Create a response callback, that will set the response and notify the condition variable - const ResponseCallbackT response_callback - = [&error, &response, signaler = std::make_shared(condition_variable, mutex, is_signaled)] - (const eCAL::service::Error& response_error, const std::shared_ptr& response_) - { - response = response_; - error = response_error; - }; - async_call_successful = async_call_service(request, response_callback); - } - - if(async_call_successful) - { - // Lock mutex, call service asynchronously and wait for the condition variable to be notified - std::unique_lock lock(mutex); - condition_variable.wait(lock, [&is_signaled]() { return is_signaled; }); - return error; - } - else - { - // If the async service call has not been successfull, that means that - // the user has stopped the client session. In that case, the request - // hasn't even been enqueued, as there is no way to make sure that the - // io_context is still being executed. In that case, we must not wait - // for it to unblock the condition variable. - // Thus, we just return an error - return eCAL::service::Error::ErrorCode::STOPPED_BY_USER; - } + // If the async service call has not been successfull, that means that + // the user has stopped the client session. In that case, the request + // hasn't even been enqueued, as there is no way to make sure that the + // io_context is still being executed. In that case, we must not wait + // for it to unblock the condition variable. + // Thus, we just return an error + return ecal_service::Error::ErrorCode::STOPPED_BY_USER; } - - State ClientSession::get_state() const { return impl_->get_state(); } - std::uint8_t ClientSession::get_accepted_protocol_version() const { return impl_->get_accepted_protocol_version(); } - int ClientSession::get_queue_size() const { return impl_->get_queue_size(); } - std::string ClientSession::get_host() const { return impl_->get_host(); } - asio::ip::tcp::endpoint ClientSession::get_remote_endpoint() const { return impl_->get_remote_endpoint(); } - std::uint16_t ClientSession::get_port() const { return impl_->get_port(); } - void ClientSession::stop() { impl_->stop(); } - } // namespace service -} // namespace eCAL + } + + State ClientSession::get_state() const { return impl_->get_state(); } + std::uint8_t ClientSession::get_accepted_protocol_version() const { return impl_->get_accepted_protocol_version(); } + int ClientSession::get_queue_size() const { return impl_->get_queue_size(); } + std::string ClientSession::get_host() const { return impl_->get_host(); } + asio::ip::tcp::endpoint ClientSession::get_remote_endpoint() const { return impl_->get_remote_endpoint(); } + std::uint16_t ClientSession::get_port() const { return impl_->get_port(); } + void ClientSession::stop() { impl_->stop(); } +} // namespace ecal_service diff --git a/ecal/service/ecal_service/src/client_session_impl_base.h b/ecal/service/ecal_service/src/client_session_impl_base.h index 6db29e96c1..0afc7b5aed 100644 --- a/ecal/service/ecal_service/src/client_session_impl_base.h +++ b/ecal/service/ecal_service/src/client_session_impl_base.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,67 +32,64 @@ #pragma warning(pop) #endif -#include +#include -#include +#include -namespace eCAL +namespace ecal_service { - namespace service + class ClientSessionBase { - class ClientSessionBase - { - ///////////////////////////////////// - // Custom types for API - ///////////////////////////////////// - public: - using EventCallbackT = eCAL::service::ClientEventCallbackT; - using ResponseCallbackT = eCAL::service::ClientResponseCallbackT; + ///////////////////////////////////// + // Custom types for API + ///////////////////////////////////// + public: + using EventCallbackT = ecal_service::ClientEventCallbackT; + using ResponseCallbackT = ecal_service::ClientResponseCallbackT; - ///////////////////////////////////// - // Constructor, Destructor, Create - ///////////////////////////////////// - protected: - ClientSessionBase(const std::shared_ptr& io_context_, const EventCallbackT& event_callback) - : io_context_ (io_context_) - , socket_ (*io_context_) - , event_callback_(event_callback) - {} + ///////////////////////////////////// + // Constructor, Destructor, Create + ///////////////////////////////////// + protected: + ClientSessionBase(const std::shared_ptr& io_context_, const EventCallbackT& event_callback) + : io_context_ (io_context_) + , socket_ (*io_context_) + , event_callback_(event_callback) + {} - public: - ClientSessionBase(const ClientSessionBase&) = delete; - ClientSessionBase(ClientSessionBase&&) = delete; - ClientSessionBase& operator=(const ClientSessionBase&) = delete; - ClientSessionBase& operator=(ClientSessionBase&&) = delete; + public: + ClientSessionBase(const ClientSessionBase&) = delete; + ClientSessionBase(ClientSessionBase&&) = delete; + ClientSessionBase& operator=(const ClientSessionBase&) = delete; + ClientSessionBase& operator=(ClientSessionBase&&) = delete; - virtual ~ClientSessionBase() = default; + virtual ~ClientSessionBase() = default; - ///////////////////////////////////// - // API - ///////////////////////////////////// - public: - virtual bool async_call_service(const std::shared_ptr& request, const ResponseCallbackT& response_callback) = 0; + ///////////////////////////////////// + // API + ///////////////////////////////////// + public: + virtual bool async_call_service(const std::shared_ptr& request, const ResponseCallbackT& response_callback) = 0; - virtual std::string get_host() const = 0; - virtual std::uint16_t get_port() const = 0; - virtual asio::ip::tcp::endpoint get_remote_endpoint() const = 0; + virtual std::string get_host() const = 0; + virtual std::uint16_t get_port() const = 0; + virtual asio::ip::tcp::endpoint get_remote_endpoint() const = 0; - virtual State get_state() const = 0; - virtual std::uint8_t get_accepted_protocol_version() const = 0; - virtual int get_queue_size() const = 0; + virtual State get_state() const = 0; + virtual std::uint8_t get_accepted_protocol_version() const = 0; + virtual int get_queue_size() const = 0; - virtual void stop() = 0; + virtual void stop() = 0; - ///////////////////////////////////// - // Member variables - ///////////////////////////////////// - protected: - const std::shared_ptr io_context_; - asio::ip::tcp::socket socket_; - mutable std::mutex socket_mutex_; - const EventCallbackT event_callback_; + ///////////////////////////////////// + // Member variables + ///////////////////////////////////// + protected: + const std::shared_ptr io_context_; + asio::ip::tcp::socket socket_; + mutable std::mutex socket_mutex_; + const EventCallbackT event_callback_; - }; + }; - } // namespace service -} // namespace eCAL +} // namespace ecal_service diff --git a/ecal/service/ecal_service/src/client_session_impl_v1.cpp b/ecal/service/ecal_service/src/client_session_impl_v1.cpp index 96a6f74d43..09df55e288 100644 --- a/ecal/service/ecal_service/src/client_session_impl_v1.cpp +++ b/ecal/service/ecal_service/src/client_session_impl_v1.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2024 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,10 +36,10 @@ #include -#include -#include -#include -#include +#include +#include +#include +#include #ifdef WIN32 #include @@ -47,673 +47,670 @@ #include #endif -namespace eCAL +namespace ecal_service { - namespace service + constexpr std::uint8_t ClientSessionV1::MIN_SUPPORTED_PROTOCOL_VERSION; + constexpr std::uint8_t ClientSessionV1::MAX_SUPPORTED_PROTOCOL_VERSION; + + ///////////////////////////////////// + // Constructor, Destructor, Create + ///////////////////////////////////// + std::shared_ptr ClientSessionV1::create(const std::shared_ptr& io_context + , const std::vector>& server_list + , const EventCallbackT& event_callback + , const LoggerT& logger) { - constexpr std::uint8_t ClientSessionV1::MIN_SUPPORTED_PROTOCOL_VERSION; - constexpr std::uint8_t ClientSessionV1::MAX_SUPPORTED_PROTOCOL_VERSION; - - ///////////////////////////////////// - // Constructor, Destructor, Create - ///////////////////////////////////// - std::shared_ptr ClientSessionV1::create(const std::shared_ptr& io_context - , const std::vector>& server_list - , const EventCallbackT& event_callback - , const LoggerT& logger) - { - std::shared_ptr instance(new ClientSessionV1(io_context, server_list, event_callback, logger)); - - // Throw exception, if the server list is empty - if (server_list.empty()) - { - throw std::invalid_argument("Server list must not be empty"); - } - - instance->resolve_endpoint(0); + std::shared_ptr instance(new ClientSessionV1(io_context, server_list, event_callback, logger)); - return instance; - } - - ClientSessionV1::ClientSessionV1(const std::shared_ptr& io_context - , const std::vector>& server_list - , const EventCallbackT& event_callback - , const LoggerT& logger) - : ClientSessionBase(io_context, event_callback) - , server_list_ (server_list) - , service_call_queue_strand_(*io_context) - , resolver_ (*io_context) - , logger_ (logger) - , accepted_protocol_version_(0) - , state_ (State::NOT_CONNECTED) - , stopped_by_user_ (false) - , service_call_in_progress_ (false) + // Throw exception, if the server list is empty + if (server_list.empty()) { - ECAL_SERVICE_LOG_DEBUG_VERBOSE(logger_, "Created"); + throw std::invalid_argument("Server list must not be empty"); } - ClientSessionV1::~ClientSessionV1() - { - ClientSessionV1::stop(); - ECAL_SERVICE_LOG_DEBUG_VERBOSE(logger_, "Deleted"); - } + instance->resolve_endpoint(0); + + return instance; + } + + ClientSessionV1::ClientSessionV1(const std::shared_ptr& io_context + , const std::vector>& server_list + , const EventCallbackT& event_callback + , const LoggerT& logger) + : ClientSessionBase(io_context, event_callback) + , server_list_ (server_list) + , service_call_queue_strand_(*io_context) + , resolver_ (*io_context) + , logger_ (logger) + , accepted_protocol_version_(0) + , state_ (State::NOT_CONNECTED) + , stopped_by_user_ (false) + , service_call_in_progress_ (false) + { + ECAL_SERVICE_LOG_DEBUG_VERBOSE(logger_, "Created"); + } - ////////////////////////////////////// - // Connection establishement - ////////////////////////////////////// - void ClientSessionV1::resolve_endpoint(size_t server_list_index) - { - ECAL_SERVICE_LOG_DEBUG(logger_, "Resolving endpoint [" + server_list_[server_list_index].first + ":" + std::to_string(server_list_[server_list_index].second) + "]..."); + ClientSessionV1::~ClientSessionV1() + { + ClientSessionV1::stop(); + ECAL_SERVICE_LOG_DEBUG_VERBOSE(logger_, "Deleted"); + } + + ////////////////////////////////////// + // Connection establishement + ////////////////////////////////////// + void ClientSessionV1::resolve_endpoint(size_t server_list_index) + { + ECAL_SERVICE_LOG_DEBUG(logger_, "Resolving endpoint [" + server_list_[server_list_index].first + ":" + std::to_string(server_list_[server_list_index].second) + "]..."); - const asio::ip::tcp::resolver::query query(server_list_[server_list_index].first, std::to_string(server_list_[server_list_index].second)); + const asio::ip::tcp::resolver::query query(server_list_[server_list_index].first, std::to_string(server_list_[server_list_index].second)); - resolver_.async_resolve(query - , service_call_queue_strand_.wrap([me = enable_shared_from_this::shared_from_this(), server_list_index_copy = server_list_index] - (asio::error_code ec, const asio::ip::tcp::resolver::iterator& resolved_endpoints) + resolver_.async_resolve(query + , service_call_queue_strand_.wrap([me = enable_shared_from_this::shared_from_this(), server_list_index_copy = server_list_index] + (asio::error_code ec, const asio::ip::tcp::resolver::iterator& resolved_endpoints) + { + if (ec) { - if (ec) - { #if ECAL_SERVICE_LOG_DEBUG_ENABLED - { - const std::string message = "Failed resolving endpoint [" + me->server_list_[server_list_index_copy].first + ":" + std::to_string(me->server_list_[server_list_index_copy].second) + "]: " + ec.message(); - ECAL_SERVICE_LOG_DEBUG(me->logger_, message); - } + { + const std::string message = "Failed resolving endpoint [" + me->server_list_[server_list_index_copy].first + ":" + std::to_string(me->server_list_[server_list_index_copy].second) + "]: " + ec.message(); + ECAL_SERVICE_LOG_DEBUG(me->logger_, message); + } #endif - if (server_list_index_copy + 1 < me->server_list_.size()) - { - // Try next possible endpoint - me->resolve_endpoint(server_list_index_copy + 1); - } - else - { - std::string message = "Failed resolving any endpoint: "; - for (size_t j = 0; j < me->server_list_.size(); ++j) - { - message += me->server_list_[j].first + ":" + std::to_string(me->server_list_[j].second); - if (j + 1 < me->server_list_.size()) - { - message += ", "; - } - } - me->logger_(LogLevel::Error, message); - me->handle_connection_loss_error(message); - } - return; + if (server_list_index_copy + 1 < me->server_list_.size()) + { + // Try next possible endpoint + me->resolve_endpoint(server_list_index_copy + 1); } else { -#if ECAL_SERVICE_LOG_DEBUG_VERBOSE_ENABLED - // Verbose-debug log of all endpoints + std::string message = "Failed resolving any endpoint: "; + for (size_t j = 0; j < me->server_list_.size(); ++j) { - std::string endpoints_str = "Resolved endpoints for " + me->server_list_[server_list_index_copy].first + ": "; - for (auto it = resolved_endpoints; it != asio::ip::tcp::resolver::iterator(); ++it) + message += me->server_list_[j].first + ":" + std::to_string(me->server_list_[j].second); + if (j + 1 < me->server_list_.size()) { - endpoints_str += endpoint_to_string(*it) + ", "; + message += ", "; } - ECAL_SERVICE_LOG_DEBUG_VERBOSE(me->logger_, endpoints_str); } -#endif //ECAL_SERVICE_LOG_DEBUG_VERBOSE_ENABLED - me->connect_to_endpoint(resolved_endpoints, server_list_index_copy); + me->logger_(LogLevel::Error, message); + me->handle_connection_loss_error(message); } - })); - } - - void ClientSessionV1::connect_to_endpoint(const asio::ip::tcp::resolver::iterator& resolved_endpoints, size_t server_list_index) - { - // Convert the resolved_endpoints iterator to an endpoint sequence - // (i.e. a vector of endpoints) - auto endpoint_sequence = std::make_shared>(); - for (auto it = resolved_endpoints; it != asio::ip::tcp::resolver::iterator(); ++it) - { - endpoint_sequence->push_back(*it); - } - - const std::lock_guard socket_lock(socket_mutex_); - asio::async_connect(socket_ - , *endpoint_sequence - , service_call_queue_strand_.wrap([me = shared_from_this(), endpoint_sequence, server_list_index](asio::error_code ec, const asio::ip::tcp::endpoint& endpoint) - { - (void)endpoint; - if (ec) - { - { - // Log an error - const std::string message = "Failed to connect to endpoint [" + me->chosen_endpoint_.first + ":" + std::to_string(me->chosen_endpoint_.second) + "]: " + ec.message(); - me->logger_(LogLevel::Error, message); - } - - // If there are more servers available, try the next one - if (server_list_index + 1 < me->server_list_.size()) - { - me->resolve_endpoint(server_list_index + 1); + return; } else { - std::string message = "Failed to connect to any endpoint: "; - for (size_t j = 0; j < me->server_list_.size(); ++j) +#if ECAL_SERVICE_LOG_DEBUG_VERBOSE_ENABLED + // Verbose-debug log of all endpoints { - message += me->server_list_[j].first + ":" + std::to_string(me->server_list_[j].second); - if (j + 1 < me->server_list_.size()) + std::string endpoints_str = "Resolved endpoints for " + me->server_list_[server_list_index_copy].first + ": "; + for (auto it = resolved_endpoints; it != asio::ip::tcp::resolver::iterator(); ++it) { - message += ", "; + endpoints_str += endpoint_to_string(*it) + ", "; } + ECAL_SERVICE_LOG_DEBUG_VERBOSE(me->logger_, endpoints_str); } - me->logger_(LogLevel::Error, message); - me->handle_connection_loss_error(message); +#endif //ECAL_SERVICE_LOG_DEBUG_VERBOSE_ENABLED + me->connect_to_endpoint(resolved_endpoints, server_list_index_copy); } - return; + })); + } + + void ClientSessionV1::connect_to_endpoint(const asio::ip::tcp::resolver::iterator& resolved_endpoints, size_t server_list_index) + { + // Convert the resolved_endpoints iterator to an endpoint sequence + // (i.e. a vector of endpoints) + auto endpoint_sequence = std::make_shared>(); + for (auto it = resolved_endpoints; it != asio::ip::tcp::resolver::iterator(); ++it) + { + endpoint_sequence->push_back(*it); + } + + const std::lock_guard socket_lock(socket_mutex_); + asio::async_connect(socket_ + , *endpoint_sequence + , service_call_queue_strand_.wrap([me = shared_from_this(), endpoint_sequence, server_list_index](asio::error_code ec, const asio::ip::tcp::endpoint& endpoint) + { + (void)endpoint; + if (ec) + { + { + // Log an error + const std::string message = "Failed to connect to endpoint [" + me->chosen_endpoint_.first + ":" + std::to_string(me->chosen_endpoint_.second) + "]: " + ec.message(); + me->logger_(LogLevel::Error, message); + } + + // If there are more servers available, try the next one + if (server_list_index + 1 < me->server_list_.size()) + { + me->resolve_endpoint(server_list_index + 1); } else { - ECAL_SERVICE_LOG_DEBUG(me->logger_, "Successfully connected to endpoint [" + endpoint.address().to_string() + ":" + std::to_string(endpoint.port()) + "]"); - - // Disable Nagle's algorithm. Nagles Algorithm will otherwise cause the - // Socket to wait for more data, if it encounters a frame that can still - // fit more data. Obviously, this is an awfull default behaviour, if we - // want to transmit our data in a timely fashion. + std::string message = "Failed to connect to any endpoint: "; + for (size_t j = 0; j < me->server_list_.size(); ++j) { - asio::error_code socket_option_ec; + message += me->server_list_[j].first + ":" + std::to_string(me->server_list_[j].second); + if (j + 1 < me->server_list_.size()) { - const std::lock_guard socket_lock(me->socket_mutex_); - me->socket_.set_option(asio::ip::tcp::no_delay(true), socket_option_ec); // NOLINT(bugprone-unused-return-value) -> We already get the value from the ec parameter + message += ", "; } - if (socket_option_ec) - { - me->logger_(LogLevel::Warning, "[" + get_connection_info_string(me->socket_) + "] " + "Failed setting tcp::no_delay option: " + socket_option_ec.message()); - } } + me->logger_(LogLevel::Error, message); + me->handle_connection_loss_error(message); + } + return; + } + else + { + ECAL_SERVICE_LOG_DEBUG(me->logger_, "Successfully connected to endpoint [" + endpoint.address().to_string() + ":" + std::to_string(endpoint.port()) + "]"); + // Disable Nagle's algorithm. Nagles Algorithm will otherwise cause the + // Socket to wait for more data, if it encounters a frame that can still + // fit more data. Obviously, this is an awfull default behaviour, if we + // want to transmit our data in a timely fashion. + { + asio::error_code socket_option_ec; { - const std::lock_guard chosen_endpoint_lock(me->chosen_endpoint_mutex_); - me->chosen_endpoint_ = me->server_list_[server_list_index]; + const std::lock_guard socket_lock(me->socket_mutex_); + me->socket_.set_option(asio::ip::tcp::no_delay(true), socket_option_ec); // NOLINT(bugprone-unused-return-value) -> We already get the value from the ec parameter } + if (socket_option_ec) + { + me->logger_(LogLevel::Warning, "[" + get_connection_info_string(me->socket_) + "] " + "Failed setting tcp::no_delay option: " + socket_option_ec.message()); + } + } - // Start sending the protocol handshake to the server. This will tell us the actual protocol version. - me->send_protocol_handshake_request(); + { + const std::lock_guard chosen_endpoint_lock(me->chosen_endpoint_mutex_); + me->chosen_endpoint_ = me->server_list_[server_list_index]; } - })); - } - void ClientSessionV1::send_protocol_handshake_request() + // Start sending the protocol handshake to the server. This will tell us the actual protocol version. + me->send_protocol_handshake_request(); + } + })); + } + + void ClientSessionV1::send_protocol_handshake_request() + { + ECAL_SERVICE_LOG_DEBUG(logger_, "[" + get_connection_info_string(socket_) + "] " + "Sending protocol handshake request..."); + + // Go to handshake state { - ECAL_SERVICE_LOG_DEBUG(logger_, "[" + get_connection_info_string(socket_) + "] " + "Sending protocol handshake request..."); + const std::lock_guard lock(service_state_mutex_); + state_ = State::HANDSHAKE; + } - // Go to handshake state - { - const std::lock_guard lock(service_state_mutex_); - state_ = State::HANDSHAKE; - } + // Create buffers + const std::shared_ptr header_buffer = std::make_shared(); + const std::shared_ptr payload_buffer = std::make_shared(); - // Create buffers - const std::shared_ptr header_buffer = std::make_shared(); - const std::shared_ptr payload_buffer = std::make_shared(); + // Fill Handshake Request Message + payload_buffer->resize(sizeof(ProtocolHandshakeRequestMessage), '\0'); + ProtocolHandshakeRequestMessage* handshake_request_message = reinterpret_cast(const_cast(payload_buffer->data())); + handshake_request_message->min_supported_protocol_version = MIN_SUPPORTED_PROTOCOL_VERSION; + handshake_request_message->max_supported_protocol_version = MAX_SUPPORTED_PROTOCOL_VERSION; - // Fill Handshake Request Message - payload_buffer->resize(sizeof(ProtocolHandshakeRequestMessage), '\0'); - ProtocolHandshakeRequestMessage* handshake_request_message = reinterpret_cast(const_cast(payload_buffer->data())); - handshake_request_message->min_supported_protocol_version = MIN_SUPPORTED_PROTOCOL_VERSION; - handshake_request_message->max_supported_protocol_version = MAX_SUPPORTED_PROTOCOL_VERSION; + // Fill TCP Header + header_buffer->package_size_n = htonl(sizeof(ProtocolHandshakeRequestMessage)); + header_buffer->version = 1; + header_buffer->message_type = MessageType::ProtocolHandshakeRequest; + header_buffer->header_size_n = htons(sizeof(TcpHeaderV1)); - // Fill TCP Header - header_buffer->package_size_n = htonl(sizeof(ProtocolHandshakeRequestMessage)); - header_buffer->version = 1; - header_buffer->message_type = MessageType::ProtocolHandshakeRequest; - header_buffer->header_size_n = htons(sizeof(TcpHeaderV1)); + ecal_service::ProtocolV1::async_send_payload(socket_, socket_mutex_, header_buffer, payload_buffer + , service_call_queue_strand_.wrap([me = shared_from_this()](asio::error_code ec) + { + const std::string message = "Failed sending protocol handshake request: " + ec.message(); + me->logger_(LogLevel::Error, "[" + get_connection_info_string(me->socket_) + "] " + message); + me->handle_connection_loss_error(message); + }) + , [me = shared_from_this()]() + { + ECAL_SERVICE_LOG_DEBUG_VERBOSE(me->logger_, "[" + get_connection_info_string(me->socket_) + "] " + "Successfully sent protocol handshake request."); + me->receive_protocol_handshake_response(); + }); + } + + void ClientSessionV1::receive_protocol_handshake_response() + { + ECAL_SERVICE_LOG_DEBUG(logger_, "[" + get_connection_info_string(socket_) + "] " + "Waiting for protocol handshake response..."); - eCAL::service::ProtocolV1::async_send_payload(socket_, socket_mutex_, header_buffer, payload_buffer + ecal_service::ProtocolV1::async_receive_payload(socket_, socket_mutex_ , service_call_queue_strand_.wrap([me = shared_from_this()](asio::error_code ec) { - const std::string message = "Failed sending protocol handshake request: " + ec.message(); + const std::string message = "Failed receiving protocol handshake response: " + ec.message(); me->logger_(LogLevel::Error, "[" + get_connection_info_string(me->socket_) + "] " + message); me->handle_connection_loss_error(message); }) - , [me = shared_from_this()]() + , service_call_queue_strand_.wrap([me = shared_from_this()](const std::shared_ptr>& header_buffer, const std::shared_ptr& payload_buffer) { - ECAL_SERVICE_LOG_DEBUG_VERBOSE(me->logger_, "[" + get_connection_info_string(me->socket_) + "] " + "Successfully sent protocol handshake request."); - me->receive_protocol_handshake_response(); - }); - } - - void ClientSessionV1::receive_protocol_handshake_response() - { - ECAL_SERVICE_LOG_DEBUG(logger_, "[" + get_connection_info_string(socket_) + "] " + "Waiting for protocol handshake response..."); - - eCAL::service::ProtocolV1::async_receive_payload(socket_, socket_mutex_ - , service_call_queue_strand_.wrap([me = shared_from_this()](asio::error_code ec) + TcpHeaderV1* header = reinterpret_cast(header_buffer->data()); + if (header->message_type != ecal_service::MessageType::ProtocolHandshakeResponse) { - const std::string message = "Failed receiving protocol handshake response: " + ec.message(); - me->logger_(LogLevel::Error, "[" + get_connection_info_string(me->socket_) + "] " + message); + // The response is not a Handshake response. + const std::string message = "Received invalid handshake response from server. Expected message type " + + std::to_string(static_cast(ecal_service::MessageType::ProtocolHandshakeResponse)) + + ", but received " + std::to_string(static_cast(header->message_type)); + me->logger_(LogLevel::Fatal, "[" + get_connection_info_string(me->socket_) + "] " + message); + me->handle_connection_loss_error(message); - }) - , service_call_queue_strand_.wrap([me = shared_from_this()](const std::shared_ptr>& header_buffer, const std::shared_ptr& payload_buffer) + return; + } + else { - TcpHeaderV1* header = reinterpret_cast(header_buffer->data()); - if (header->message_type != eCAL::service::MessageType::ProtocolHandshakeResponse) - { - // The response is not a Handshake response. - const std::string message = "Received invalid handshake response from server. Expected message type " - + std::to_string(static_cast(eCAL::service::MessageType::ProtocolHandshakeResponse)) - + ", but received " + std::to_string(static_cast(header->message_type)); - me->logger_(LogLevel::Fatal, "[" + get_connection_info_string(me->socket_) + "] " + message); + // The response is a Handshake response + ECAL_SERVICE_LOG_DEBUG_VERBOSE(me->logger_, "[" + get_connection_info_string(me->socket_) + "] " + "Received a handshake response of " + std::to_string(payload_buffer->size()) + " bytes."); - me->handle_connection_loss_error(message); - return; - } - else + // Resize payload if necessary. Will probably never be necessary + if (payload_buffer->size() < sizeof(ProtocolHandshakeResponseMessage)) { - // The response is a Handshake response - ECAL_SERVICE_LOG_DEBUG_VERBOSE(me->logger_, "[" + get_connection_info_string(me->socket_) + "] " + "Received a handshake response of " + std::to_string(payload_buffer->size()) + " bytes."); + payload_buffer->resize(sizeof(ProtocolHandshakeResponseMessage), '\0'); + } + const ProtocolHandshakeResponseMessage* handshake_response = reinterpret_cast(payload_buffer->data()); - // Resize payload if necessary. Will probably never be necessary - if (payload_buffer->size() < sizeof(ProtocolHandshakeResponseMessage)) + if ((handshake_response->accepted_protocol_version >= MIN_SUPPORTED_PROTOCOL_VERSION) + && (handshake_response->accepted_protocol_version <= MIN_SUPPORTED_PROTOCOL_VERSION)) + { { - payload_buffer->resize(sizeof(ProtocolHandshakeResponseMessage), '\0'); + const std::lock_guard lock(me->service_state_mutex_); + me->accepted_protocol_version_ = handshake_response->accepted_protocol_version; + me->state_ = State::CONNECTED; } - const ProtocolHandshakeResponseMessage* handshake_response = reinterpret_cast(payload_buffer->data()); - if ((handshake_response->accepted_protocol_version >= MIN_SUPPORTED_PROTOCOL_VERSION) - && (handshake_response->accepted_protocol_version <= MIN_SUPPORTED_PROTOCOL_VERSION)) + const std::string message = "Connected to server. Using protocol version " + std::to_string(me->accepted_protocol_version_); + me->logger_(LogLevel::Info, "[" + get_connection_info_string(me->socket_) + "] " + message); + + // Call event callback + if(me->event_callback_) me->event_callback_(ecal_service::ClientEventType::Connected, message); + + // Start sending service requests, if there are any { + const std::lock_guard lock(me->service_state_mutex_); + if (!me->service_call_queue_.empty()) { - const std::lock_guard lock(me->service_state_mutex_); - me->accepted_protocol_version_ = handshake_response->accepted_protocol_version; - me->state_ = State::CONNECTED; + // If there are service calls in the queue, we send the next one. + me->service_call_in_progress_ = true; + me->send_next_service_request(me->service_call_queue_.front().request, me->service_call_queue_.front().response_cb); + me->service_call_queue_.pop_front(); } - - const std::string message = "Connected to server. Using protocol version " + std::to_string(me->accepted_protocol_version_); - me->logger_(LogLevel::Info, "[" + get_connection_info_string(me->socket_) + "] " + message); - - // Call event callback - if(me->event_callback_) me->event_callback_(eCAL::service::ClientEventType::Connected, message); - - // Start sending service requests, if there are any + else { - const std::lock_guard lock(me->service_state_mutex_); - if (!me->service_call_queue_.empty()) - { - // If there are service calls in the queue, we send the next one. - me->service_call_in_progress_ = true; - me->send_next_service_request(me->service_call_queue_.front().request, me->service_call_queue_.front().response_cb); - me->service_call_queue_.pop_front(); - } - else - { - // If there are no more service calls to send, we go to error-peeking. - // While error peeking we basically do nothing, except from non-destructively - // reading 1 byte from the socket (i.e. without removing it from the socket). - // This will cause asio / the OS to notify us, when the server closed the connection. + // If there are no more service calls to send, we go to error-peeking. + // While error peeking we basically do nothing, except from non-destructively + // reading 1 byte from the socket (i.e. without removing it from the socket). + // This will cause asio / the OS to notify us, when the server closed the connection. - me->service_call_in_progress_ = false; - me->peek_for_error(); - } + me->service_call_in_progress_ = false; + me->peek_for_error(); } - - return; } - else - { - const std::string message = "Error connecting to server. Server reported an un-supported protocol version: " + std::to_string(handshake_response->accepted_protocol_version); - me->logger_(LogLevel::Error, "[" + get_connection_info_string(me->socket_) + "] " + message); - me->handle_connection_loss_error(message); - return; - } + return; + } + else + { + const std::string message = "Error connecting to server. Server reported an un-supported protocol version: " + std::to_string(handshake_response->accepted_protocol_version); + me->logger_(LogLevel::Error, "[" + get_connection_info_string(me->socket_) + "] " + message); + me->handle_connection_loss_error(message); + return; } - })); - } - ////////////////////////////////////// - // Service calls - ////////////////////////////////////// + } + })); + } + + ////////////////////////////////////// + // Service calls + ////////////////////////////////////// - bool ClientSessionV1::async_call_service(const std::shared_ptr& request, const ResponseCallbackT& response_callback) + bool ClientSessionV1::async_call_service(const std::shared_ptr& request, const ResponseCallbackT& response_callback) + { + // Lock mutex for stopped_by_user_ variable + const std::lock_guard service_state_lock(service_state_mutex_); + + if (stopped_by_user_) { - // Lock mutex for stopped_by_user_ variable - const std::lock_guard service_state_lock(service_state_mutex_); - - if (stopped_by_user_) - { - return false; - } - else - { - service_call_queue_strand_.post([me = shared_from_this(), request, response_callback]() + return false; + } + else + { + service_call_queue_strand_.post([me = shared_from_this(), request, response_callback]() + { + // Variable that enables us to unlock the mutex before actually calling the callback + bool call_response_callback_with_error(false); + { - // Variable that enables us to unlock the mutex before actually calling the callback - bool call_response_callback_with_error(false); - + const std::lock_guard lock(me->service_state_mutex_); + if (me->state_ != State::FAILED) { - const std::lock_guard lock(me->service_state_mutex_); - if (me->state_ != State::FAILED) - { - // If we are not in failed state, let's check - // whether we directly invoke the call of if we add it to the queue + // If we are not in failed state, let's check + // whether we directly invoke the call of if we add it to the queue - if (!me->service_call_in_progress_ && (me->state_ == State::CONNECTED)) - { - // Directly call the the service, iff - // - // - There is no call in progress - // - // and - // - // - We are connected - // - ECAL_SERVICE_LOG_DEBUG_VERBOSE(me->logger_, "[" + get_connection_info_string(me->socket_) + "] " + " No service call in progress. Directly starting next service call."); - me->service_call_in_progress_ = true; - me->send_next_service_request(request, response_callback); - } - else - { - // Add the call to the queue, iff: - // - // - A call is already in progress - // - // or - // - // - We are not connected, yet - // - ECAL_SERVICE_LOG_DEBUG_VERBOSE(me->logger_, "[" + get_connection_info_string(me->socket_) + "] " + "Queuing new service request"); - me->service_call_queue_.push_back(ServiceCall{request, response_callback}); - } + if (!me->service_call_in_progress_ && (me->state_ == State::CONNECTED)) + { + // Directly call the the service, iff + // + // - There is no call in progress + // + // and + // + // - We are connected + // + ECAL_SERVICE_LOG_DEBUG_VERBOSE(me->logger_, "[" + get_connection_info_string(me->socket_) + "] " + " No service call in progress. Directly starting next service call."); + me->service_call_in_progress_ = true; + me->send_next_service_request(request, response_callback); } else { - // If we are in FAILED state, we directly call the callback with an error. - call_response_callback_with_error = true; + // Add the call to the queue, iff: + // + // - A call is already in progress + // + // or + // + // - We are not connected, yet + // + ECAL_SERVICE_LOG_DEBUG_VERBOSE(me->logger_, "[" + get_connection_info_string(me->socket_) + "] " + "Queuing new service request"); + me->service_call_queue_.push_back(ServiceCall{request, response_callback}); } } - - if(call_response_callback_with_error) + else { // If we are in FAILED state, we directly call the callback with an error. - // The mutex is unlocked at this point. That is important, as we have no - // influence on when the callback will return. - ECAL_SERVICE_LOG_DEBUG_VERBOSE(me->logger_, "[" + get_connection_info_string(me->socket_) + "] " + " Client is in FAILED state. Calling callback with error."); - response_callback(eCAL::service::Error::ErrorCode::CONNECTION_CLOSED, nullptr); + call_response_callback_with_error = true; } - }); - return true; - } - } - - void ClientSessionV1::send_next_service_request(const std::shared_ptr& request, const ResponseCallbackT& response_cb) - { - ECAL_SERVICE_LOG_DEBUG(logger_, "[" + get_connection_info_string(socket_) + "] " + "Sending service request..."); - - // Create header_buffer - const std::shared_ptr header_buffer = std::make_shared(); - header_buffer->package_size_n = htonl(static_cast(request->size())); - header_buffer->version = accepted_protocol_version_; - header_buffer->message_type = MessageType::ServiceRequest; - header_buffer->header_size_n = htons(sizeof(TcpHeaderV1)); - - eCAL::service::ProtocolV1::async_send_payload(socket_, socket_mutex_, header_buffer, request - , service_call_queue_strand_.wrap([me = shared_from_this(), response_cb](asio::error_code ec) - { - const std::string message = "Failed sending service request: " + ec.message(); - me->logger_(LogLevel::Error, "[" + get_connection_info_string(me->socket_) + "] " + message); + } - // Call the callback with an error - response_cb(Error(Error::ErrorCode::CONNECTION_CLOSED, message), nullptr); - - // Further handle the error, e.g. unwinding pending service calls and calling the event callback - me->handle_connection_loss_error(message); - }) - , [me = shared_from_this(), response_cb]() - { - ECAL_SERVICE_LOG_DEBUG_VERBOSE(me->logger_, "[" + get_connection_info_string(me->socket_) + "] " + "Successfully sent service request."); - me->receive_service_response(response_cb); - }); + if(call_response_callback_with_error) + { + // If we are in FAILED state, we directly call the callback with an error. + // The mutex is unlocked at this point. That is important, as we have no + // influence on when the callback will return. + ECAL_SERVICE_LOG_DEBUG_VERBOSE(me->logger_, "[" + get_connection_info_string(me->socket_) + "] " + " Client is in FAILED state. Calling callback with error."); + response_callback(ecal_service::Error::ErrorCode::CONNECTION_CLOSED, nullptr); + } + }); + return true; } + } - void ClientSessionV1::receive_service_response(const ResponseCallbackT& response_cb) - { - ECAL_SERVICE_LOG_DEBUG_VERBOSE(logger_, "[" + get_connection_info_string(socket_) + "] " + "Waiting for service response..."); + void ClientSessionV1::send_next_service_request(const std::shared_ptr& request, const ResponseCallbackT& response_cb) + { + ECAL_SERVICE_LOG_DEBUG(logger_, "[" + get_connection_info_string(socket_) + "] " + "Sending service request..."); - eCAL::service::ProtocolV1::async_receive_payload(socket_, socket_mutex_ + // Create header_buffer + const std::shared_ptr header_buffer = std::make_shared(); + header_buffer->package_size_n = htonl(static_cast(request->size())); + header_buffer->version = accepted_protocol_version_; + header_buffer->message_type = MessageType::ServiceRequest; + header_buffer->header_size_n = htons(sizeof(TcpHeaderV1)); + + ecal_service::ProtocolV1::async_send_payload(socket_, socket_mutex_, header_buffer, request , service_call_queue_strand_.wrap([me = shared_from_this(), response_cb](asio::error_code ec) { - const std::string message = "Failed receiving service response: " + ec.message(); + const std::string message = "Failed sending service request: " + ec.message(); me->logger_(LogLevel::Error, "[" + get_connection_info_string(me->socket_) + "] " + message); // Call the callback with an error response_cb(Error(Error::ErrorCode::CONNECTION_CLOSED, message), nullptr); - + // Further handle the error, e.g. unwinding pending service calls and calling the event callback me->handle_connection_loss_error(message); }) - , service_call_queue_strand_.wrap([me = shared_from_this(), response_cb](const std::shared_ptr>& header_buffer, const std::shared_ptr& payload_buffer) + , [me = shared_from_this(), response_cb]() { - TcpHeaderV1* header = reinterpret_cast(header_buffer->data()); - if (header->message_type != eCAL::service::MessageType::ServiceResponse) - { - const std::string message = "Received invalid service response from server. Expected message type " - + std::to_string(static_cast(eCAL::service::MessageType::ServiceResponse)) - + ", but received " + std::to_string(static_cast(header->message_type)); - me->logger_(LogLevel::Fatal, "[" + get_connection_info_string(me->socket_) + "] " + message); + ECAL_SERVICE_LOG_DEBUG_VERBOSE(me->logger_, "[" + get_connection_info_string(me->socket_) + "] " + "Successfully sent service request."); + me->receive_service_response(response_cb); + }); + } - // Call the callback with an error - response_cb(Error(Error::ErrorCode::PROTOCOL_ERROR, message), nullptr); + void ClientSessionV1::receive_service_response(const ResponseCallbackT& response_cb) + { + ECAL_SERVICE_LOG_DEBUG_VERBOSE(logger_, "[" + get_connection_info_string(socket_) + "] " + "Waiting for service response..."); - // Further handle the error, e.g. unwinding pending service calls and calling the event callback - me->handle_connection_loss_error(message); - return; - } - else - { - // The response is a Service response - ECAL_SERVICE_LOG_DEBUG(me->logger_, "[" + get_connection_info_string(me->socket_) + "] " + "Successfully received service response of " + std::to_string(payload_buffer->size()) + " bytes"); + ecal_service::ProtocolV1::async_receive_payload(socket_, socket_mutex_ + , service_call_queue_strand_.wrap([me = shared_from_this(), response_cb](asio::error_code ec) + { + const std::string message = "Failed receiving service response: " + ec.message(); + me->logger_(LogLevel::Error, "[" + get_connection_info_string(me->socket_) + "] " + message); - // Call the user's callback - response_cb(Error::OK, payload_buffer); + // Call the callback with an error + response_cb(Error(Error::ErrorCode::CONNECTION_CLOSED, message), nullptr); - // Check if there are more items in the queue. If so, send the next request - // The mutex must be locket, as we access the queue. - { - const std::lock_guard lock(me->service_state_mutex_); + // Further handle the error, e.g. unwinding pending service calls and calling the event callback + me->handle_connection_loss_error(message); + }) + , service_call_queue_strand_.wrap([me = shared_from_this(), response_cb](const std::shared_ptr>& header_buffer, const std::shared_ptr& payload_buffer) + { + TcpHeaderV1* header = reinterpret_cast(header_buffer->data()); + if (header->message_type != ecal_service::MessageType::ServiceResponse) + { + const std::string message = "Received invalid service response from server. Expected message type " + + std::to_string(static_cast(ecal_service::MessageType::ServiceResponse)) + + ", but received " + std::to_string(static_cast(header->message_type)); + me->logger_(LogLevel::Fatal, "[" + get_connection_info_string(me->socket_) + "] " + message); - if (!me->service_call_queue_.empty()) - { - // If there are more items, continue calling the service - ECAL_SERVICE_LOG_DEBUG_VERBOSE(me->logger_, "[" + get_connection_info_string(me->socket_) + "] " + " Service call queue contains " + std::to_string(me->service_call_queue_.size()) + " Entries. Starting next service call."); - me->service_call_in_progress_ = true; - me->send_next_service_request(me->service_call_queue_.front().request, me->service_call_queue_.front().response_cb); - me->service_call_queue_.pop_front(); - } - else - { - // If there are no more service calls to send, we go to error-peeking. - // While error peeking we basically do nothing, except from non-destructively - // reading 1 byte from the socket (i.e. without removing it from the socket). - // This will cause asio / the OS to notify us, when the server closed the connection. + // Call the callback with an error + response_cb(Error(Error::ErrorCode::PROTOCOL_ERROR, message), nullptr); - ECAL_SERVICE_LOG_DEBUG_VERBOSE(me->logger_, "[" + get_connection_info_string(me->socket_) + "] " + " No further servcice calls."); - me->service_call_in_progress_ = false; - me->peek_for_error(); - } + // Further handle the error, e.g. unwinding pending service calls and calling the event callback + me->handle_connection_loss_error(message); + return; + } + else + { + // The response is a Service response + ECAL_SERVICE_LOG_DEBUG(me->logger_, "[" + get_connection_info_string(me->socket_) + "] " + "Successfully received service response of " + std::to_string(payload_buffer->size()) + " bytes"); + + // Call the user's callback + response_cb(Error::OK, payload_buffer); + + // Check if there are more items in the queue. If so, send the next request + // The mutex must be locket, as we access the queue. + { + const std::lock_guard lock(me->service_state_mutex_); + + if (!me->service_call_queue_.empty()) + { + // If there are more items, continue calling the service + ECAL_SERVICE_LOG_DEBUG_VERBOSE(me->logger_, "[" + get_connection_info_string(me->socket_) + "] " + " Service call queue contains " + std::to_string(me->service_call_queue_.size()) + " Entries. Starting next service call."); + me->service_call_in_progress_ = true; + me->send_next_service_request(me->service_call_queue_.front().request, me->service_call_queue_.front().response_cb); + me->service_call_queue_.pop_front(); + } + else + { + // If there are no more service calls to send, we go to error-peeking. + // While error peeking we basically do nothing, except from non-destructively + // reading 1 byte from the socket (i.e. without removing it from the socket). + // This will cause asio / the OS to notify us, when the server closed the connection. + + ECAL_SERVICE_LOG_DEBUG_VERBOSE(me->logger_, "[" + get_connection_info_string(me->socket_) + "] " + " No further servcice calls."); + me->service_call_in_progress_ = false; + me->peek_for_error(); } } - })); + } + })); - } + } - ////////////////////////////////////// - // Status API - ////////////////////////////////////// - - std::string ClientSessionV1::get_host() const - { - const std::lock_guard chosen_endpoint_lock(chosen_endpoint_mutex_); - return chosen_endpoint_.first; - } + ////////////////////////////////////// + // Status API + ////////////////////////////////////// + + std::string ClientSessionV1::get_host() const + { + const std::lock_guard chosen_endpoint_lock(chosen_endpoint_mutex_); + return chosen_endpoint_.first; + } - std::uint16_t ClientSessionV1::get_port() const - { - const std::lock_guard chosen_endpoint_lock(chosen_endpoint_mutex_); - return chosen_endpoint_.second; - } + std::uint16_t ClientSessionV1::get_port() const + { + const std::lock_guard chosen_endpoint_lock(chosen_endpoint_mutex_); + return chosen_endpoint_.second; + } - asio::ip::tcp::endpoint ClientSessionV1::get_remote_endpoint() const - { - // form remote endpoint string - { - asio::error_code ec; - auto endpoint = socket_.remote_endpoint(ec); - if (!ec) - return endpoint; - else - return asio::ip::tcp::endpoint(); - } - } - - State ClientSessionV1::get_state() const + asio::ip::tcp::endpoint ClientSessionV1::get_remote_endpoint() const + { + // form remote endpoint string { - const std::lock_guard lock(service_state_mutex_); - return state_; + asio::error_code ec; + auto endpoint = socket_.remote_endpoint(ec); + if (!ec) + return endpoint; + else + return asio::ip::tcp::endpoint(); } + } + + State ClientSessionV1::get_state() const + { + const std::lock_guard lock(service_state_mutex_); + return state_; + } - std::uint8_t ClientSessionV1::get_accepted_protocol_version() const - { - return accepted_protocol_version_; - } + std::uint8_t ClientSessionV1::get_accepted_protocol_version() const + { + return accepted_protocol_version_; + } - int ClientSessionV1::get_queue_size() const - { - const std::lock_guard lock(service_state_mutex_); - return static_cast(service_call_queue_.size()); - } + int ClientSessionV1::get_queue_size() const + { + const std::lock_guard lock(service_state_mutex_); + return static_cast(service_call_queue_.size()); + } + + ////////////////////////////////////// + // Shutdown + ////////////////////////////////////// + void ClientSessionV1::peek_for_error() + { + const std::shared_ptr> peek_buffer = std::make_shared>(1, '\0'); - ////////////////////////////////////// - // Shutdown - ////////////////////////////////////// - void ClientSessionV1::peek_for_error() - { - const std::shared_ptr> peek_buffer = std::make_shared>(1, '\0'); + const std::lock_guard socket_lock(socket_mutex_); + socket_.async_receive(asio::buffer(*peek_buffer) + , asio::socket_base::message_peek + , service_call_queue_strand_.wrap([me = shared_from_this(), peek_buffer](const asio::error_code& ec, std::size_t /*bytes_transferred*/) { + if (ec) + { + const std::string message = "Connection loss while idling: " + ec.message(); + me->logger_(ecal_service::LogLevel::Info, "[" + get_connection_info_string(me->socket_) + "] " + message); + me->handle_connection_loss_error("Connection loss while idling: " + ec.message()); + } + })); + } - const std::lock_guard socket_lock(socket_mutex_); - socket_.async_receive(asio::buffer(*peek_buffer) - , asio::socket_base::message_peek - , service_call_queue_strand_.wrap([me = shared_from_this(), peek_buffer](const asio::error_code& ec, std::size_t /*bytes_transferred*/) { - if (ec) - { - const std::string message = "Connection loss while idling: " + ec.message(); - me->logger_(eCAL::service::LogLevel::Info, "[" + get_connection_info_string(me->socket_) + "] " + message); - me->handle_connection_loss_error("Connection loss while idling: " + ec.message()); - } - })); - } + void ClientSessionV1::handle_connection_loss_error(const std::string& error_message) + { + bool call_event_callback (false); // Variable that enables us to unlock the mutex before we execute the event callback. + + // Close the socket, so all waiting async operations are actually woken + // up and fail with an error code. If we wouldn't do that, at least on + // Ubuntu only 1 waiting operations would wake up, while the others would + // indefinitively continue to wait. + // Having multiple async operations on the same socket actually does + // happen, as we are peeking for errors whenever we don't send or + // receive anything. + close_socket(); - void ClientSessionV1::handle_connection_loss_error(const std::string& error_message) { - bool call_event_callback (false); // Variable that enables us to unlock the mutex before we execute the event callback. - - // Close the socket, so all waiting async operations are actually woken - // up and fail with an error code. If we wouldn't do that, at least on - // Ubuntu only 1 waiting operations would wake up, while the others would - // indefinitively continue to wait. - // Having multiple async operations on the same socket actually does - // happen, as we are peeking for errors whenever we don't send or - // receive anything. - close_socket(); + const std::lock_guard lock(service_state_mutex_); + // cancel the connection loss handling, if we are already in FAILED state + if (state_ == State::FAILED) + return; + + if (state_ == State::CONNECTED) { - const std::lock_guard lock(service_state_mutex_); - - // cancel the connection loss handling, if we are already in FAILED state - if (state_ == State::FAILED) - return; - - if (state_ == State::CONNECTED) - { - // Event callback - call_event_callback = true; - } - - // Set the state to FAILED - state_ = State::FAILED; - - // call all callbacks from the queue with an error - if (!service_call_queue_.empty()) - { - ECAL_SERVICE_LOG_DEBUG(logger_, "[" + get_connection_info_string(socket_) + "] " + "Calling " + std::to_string(service_call_queue_.size()) + " service callbacks with error"); - call_all_callbacks_with_error(); - } + // Event callback + call_event_callback = true; } - if (call_event_callback && event_callback_) + // Set the state to FAILED + state_ = State::FAILED; + + // call all callbacks from the queue with an error + if (!service_call_queue_.empty()) { - event_callback_(eCAL::service::ClientEventType::Disconnected, error_message); + ECAL_SERVICE_LOG_DEBUG(logger_, "[" + get_connection_info_string(socket_) + "] " + "Calling " + std::to_string(service_call_queue_.size()) + " service callbacks with error"); + call_all_callbacks_with_error(); } } - void ClientSessionV1::call_all_callbacks_with_error() + if (call_event_callback && event_callback_) { - service_call_queue_strand_.post([me = shared_from_this()]() + event_callback_(ecal_service::ClientEventType::Disconnected, error_message); + } + } + + void ClientSessionV1::call_all_callbacks_with_error() + { + service_call_queue_strand_.post([me = shared_from_this()]() + { + ServiceCall first_service_call; + bool more_service_calls(false); + { - ServiceCall first_service_call; - bool more_service_calls(false); + // Lock the mutex and manipulate the queue. We want the mutex unlocked for the event callback call. + const std::lock_guard lock(me->service_state_mutex_); + + if (me->service_call_queue_.empty()) + return; - { - // Lock the mutex and manipulate the queue. We want the mutex unlocked for the event callback call. - const std::lock_guard lock(me->service_state_mutex_); - - if (me->service_call_queue_.empty()) - return; + first_service_call = std::move(me->service_call_queue_.front()); + me->service_call_queue_.pop_front(); - first_service_call = std::move(me->service_call_queue_.front()); - me->service_call_queue_.pop_front(); + more_service_calls = (!me->service_call_queue_.empty()); + } - more_service_calls = (!me->service_call_queue_.empty()); - } + // Execute the callback with an error + first_service_call.response_cb(ecal_service::Error::ErrorCode::CONNECTION_CLOSED, nullptr); // TODO: I should probably store the error that lead to this somewhere and tell the actual error. - // Execute the callback with an error - first_service_call.response_cb(eCAL::service::Error::ErrorCode::CONNECTION_CLOSED, nullptr); // TODO: I should probably store the error that lead to this somewhere and tell the actual error. + // If there are more sevice calls, call those with an error, as well + if (more_service_calls) + me->call_all_callbacks_with_error(); + }); + } + + void ClientSessionV1::stop() + { + // This is a function that gets used both by the API and by potentially + // multiple failing async operations at once. - // If there are more sevice calls, call those with an error, as well - if (more_service_calls) - me->call_all_callbacks_with_error(); - }); + { + // Set the stopped_by_user_ flag to true, so that the async operations stop enqueuing new service calls. + const std::lock_guard service_state_lock(service_state_mutex_); + stopped_by_user_ = true; } - void ClientSessionV1::stop() { - // This is a function that gets used both by the API and by potentially - // multiple failing async operations at once. + close_socket(); + } + } - { - // Set the stopped_by_user_ flag to true, so that the async operations stop enqueuing new service calls. - const std::lock_guard service_state_lock(service_state_mutex_); - stopped_by_user_ = true; - } + void ClientSessionV1::close_socket() + { + // Close the socket, so all waiting async operations will fail with an + // error code. This will also cause the client to call all pending + // callbacks with an error. + const std::lock_guard socket_lock(socket_mutex_); + if (socket_.is_open()) + { { - close_socket(); + asio::error_code ec; + socket_.shutdown(asio::ip::tcp::socket::shutdown_both, ec); // NOLINT(bugprone-unused-return-value) -> we already get the return value from the ec parameter } - } - - void ClientSessionV1::close_socket() - { - // Close the socket, so all waiting async operations will fail with an - // error code. This will also cause the client to call all pending - // callbacks with an error. - const std::lock_guard socket_lock(socket_mutex_); - if (socket_.is_open()) { - { - asio::error_code ec; - socket_.shutdown(asio::ip::tcp::socket::shutdown_both, ec); // NOLINT(bugprone-unused-return-value) -> we already get the return value from the ec parameter - } - - { - asio::error_code ec; - socket_.close(ec); // NOLINT(bugprone-unused-return-value) -> we already get the return value from the ec parameter - } + asio::error_code ec; + socket_.close(ec); // NOLINT(bugprone-unused-return-value) -> we already get the return value from the ec parameter } } - } // namespace service -} // namespace eCAL + } +} // namespace ecal_service diff --git a/ecal/service/ecal_service/src/client_session_impl_v1.h b/ecal/service/ecal_service/src/client_session_impl_v1.h index c95d360f1e..48ac01ecb2 100644 --- a/ecal/service/ecal_service/src/client_session_impl_v1.h +++ b/ecal/service/ecal_service/src/client_session_impl_v1.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ===== ============================ * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,141 +33,138 @@ #include -#include -#include +#include +#include -namespace eCAL +namespace ecal_service { - namespace service + class ClientSessionV1 + : public ClientSessionBase + , public std::enable_shared_from_this { - class ClientSessionV1 - : public ClientSessionBase - , public std::enable_shared_from_this + ////////////////////////////////////// + // Internal types + ////////////////////////////////////// + private: + struct ServiceCall { - ////////////////////////////////////// - // Internal types - ////////////////////////////////////// - private: - struct ServiceCall - { - std::shared_ptr request; - ResponseCallbackT response_cb; - }; - - ///////////////////////////////////// - // Constructor, Destructor, Create - ///////////////////////////////////// - public: - static std::shared_ptr create(const std::shared_ptr& io_context - , const std::vector>& server_list - , const EventCallbackT& event_callback - , const LoggerT& logger_ = default_logger("Service Client V1")); - - protected: - ClientSessionV1(const std::shared_ptr& io_context - , const std::vector>& server_list - , const EventCallbackT& event_callback - , const LoggerT& logger); - - public: - // Delete copy / move constructor and assignment operator - ClientSessionV1(const ClientSessionV1&) = delete; // Copy construct - ClientSessionV1(ClientSessionV1&&) = delete; // Move construct - - ClientSessionV1& operator=(const ClientSessionV1&) = delete; // Copy assign - ClientSessionV1& operator=(ClientSessionV1&&) = delete; // Move assign - - ~ClientSessionV1() override; - - ////////////////////////////////////// - // Connection establishement - ////////////////////////////////////// - private: - void resolve_endpoint(size_t server_list_index); - void connect_to_endpoint(const asio::ip::tcp::resolver::iterator& resolved_endpoints, size_t server_list_index); - - void send_protocol_handshake_request(); - void receive_protocol_handshake_response(); - - ////////////////////////////////////// - // Service calls - ////////////////////////////////////// - public: - bool async_call_service(const std::shared_ptr& request, const ResponseCallbackT& response_callback) override; - - private: - void send_next_service_request(const std::shared_ptr& request, const ResponseCallbackT& response_cb); - void receive_service_response(const ResponseCallbackT& response_cb); - - ////////////////////////////////////// - // Status API - ////////////////////////////////////// - public: - std::string get_host() const override; - std::uint16_t get_port() const override; - asio::ip::tcp::endpoint get_remote_endpoint() const override; - - State get_state() const override; - std::uint8_t get_accepted_protocol_version() const override; - int get_queue_size() const override; - - ////////////////////////////////////// - // Shutdown - ////////////////////////////////////// - public: - void peek_for_error(); - void handle_connection_loss_error(const std::string& message); - void call_all_callbacks_with_error(); - - /** - * @brief Stop the client. - * - * This will close the connection AND set the state to stopped. This - * means, that no further async service calls will be accepted. From now - * on, all async service calls will just return false and the callback - * will not be called any more in order to give the io_thread the chance - * of shutting down. - */ - void stop() override; - - private: - /** - * @brief Closes the internal socket - * - * This will close the connection without setting the state to stopped. - * This means, that further async service calls will still be accepted, - * but they will fail. The failure is still communicated by calling the - * callback. For a proper shutdown, where the plan is to stop the - * io_context thread as well, the stop() function must be used, or the - * client must be destroyed. - */ - void close_socket(); - - - ////////////////////////////////////// - // Member variables - ////////////////////////////////////// - private: - static constexpr std::uint8_t MIN_SUPPORTED_PROTOCOL_VERSION = 1; - static constexpr std::uint8_t MAX_SUPPORTED_PROTOCOL_VERSION = 1; - - const std::vector> server_list_; //!< The list of servers that this client was created with. They will be tried in order. - - mutable std::mutex chosen_endpoint_mutex_; //!< Protects the chosen_endpoint_ variable. - std::pair chosen_endpoint_; //!< The endpoint that the client is currently connected to. Protected by chosen_endpoint_mutex_. - - asio::io_context::strand service_call_queue_strand_; - asio::ip::tcp::resolver resolver_; - const LoggerT logger_; - - std::atomic accepted_protocol_version_; - - mutable std::mutex service_state_mutex_; - State state_; //!< The connection state of this client. Protected by service_state_mutex_. - bool stopped_by_user_; //!< Telling whether we actively stopped the client. Protected by service_state_mutex_. When set, the client will not accept any more async service calls. - - std::deque service_call_queue_; - bool service_call_in_progress_; + std::shared_ptr request; + ResponseCallbackT response_cb; }; - } + + ///////////////////////////////////// + // Constructor, Destructor, Create + ///////////////////////////////////// + public: + static std::shared_ptr create(const std::shared_ptr& io_context + , const std::vector>& server_list + , const EventCallbackT& event_callback + , const LoggerT& logger_ = default_logger("Service Client V1")); + + protected: + ClientSessionV1(const std::shared_ptr& io_context + , const std::vector>& server_list + , const EventCallbackT& event_callback + , const LoggerT& logger); + + public: + // Delete copy / move constructor and assignment operator + ClientSessionV1(const ClientSessionV1&) = delete; // Copy construct + ClientSessionV1(ClientSessionV1&&) = delete; // Move construct + + ClientSessionV1& operator=(const ClientSessionV1&) = delete; // Copy assign + ClientSessionV1& operator=(ClientSessionV1&&) = delete; // Move assign + + ~ClientSessionV1() override; + + ////////////////////////////////////// + // Connection establishement + ////////////////////////////////////// + private: + void resolve_endpoint(size_t server_list_index); + void connect_to_endpoint(const asio::ip::tcp::resolver::iterator& resolved_endpoints, size_t server_list_index); + + void send_protocol_handshake_request(); + void receive_protocol_handshake_response(); + + ////////////////////////////////////// + // Service calls + ////////////////////////////////////// + public: + bool async_call_service(const std::shared_ptr& request, const ResponseCallbackT& response_callback) override; + + private: + void send_next_service_request(const std::shared_ptr& request, const ResponseCallbackT& response_cb); + void receive_service_response(const ResponseCallbackT& response_cb); + + ////////////////////////////////////// + // Status API + ////////////////////////////////////// + public: + std::string get_host() const override; + std::uint16_t get_port() const override; + asio::ip::tcp::endpoint get_remote_endpoint() const override; + + State get_state() const override; + std::uint8_t get_accepted_protocol_version() const override; + int get_queue_size() const override; + + ////////////////////////////////////// + // Shutdown + ////////////////////////////////////// + public: + void peek_for_error(); + void handle_connection_loss_error(const std::string& message); + void call_all_callbacks_with_error(); + + /** + * @brief Stop the client. + * + * This will close the connection AND set the state to stopped. This + * means, that no further async service calls will be accepted. From now + * on, all async service calls will just return false and the callback + * will not be called any more in order to give the io_thread the chance + * of shutting down. + */ + void stop() override; + + private: + /** + * @brief Closes the internal socket + * + * This will close the connection without setting the state to stopped. + * This means, that further async service calls will still be accepted, + * but they will fail. The failure is still communicated by calling the + * callback. For a proper shutdown, where the plan is to stop the + * io_context thread as well, the stop() function must be used, or the + * client must be destroyed. + */ + void close_socket(); + + + ////////////////////////////////////// + // Member variables + ////////////////////////////////////// + private: + static constexpr std::uint8_t MIN_SUPPORTED_PROTOCOL_VERSION = 1; + static constexpr std::uint8_t MAX_SUPPORTED_PROTOCOL_VERSION = 1; + + const std::vector> server_list_; //!< The list of servers that this client was created with. They will be tried in order. + + mutable std::mutex chosen_endpoint_mutex_; //!< Protects the chosen_endpoint_ variable. + std::pair chosen_endpoint_; //!< The endpoint that the client is currently connected to. Protected by chosen_endpoint_mutex_. + + asio::io_context::strand service_call_queue_strand_; + asio::ip::tcp::resolver resolver_; + const LoggerT logger_; + + std::atomic accepted_protocol_version_; + + mutable std::mutex service_state_mutex_; + State state_; //!< The connection state of this client. Protected by service_state_mutex_. + bool stopped_by_user_; //!< Telling whether we actively stopped the client. Protected by service_state_mutex_. When set, the client will not accept any more async service calls. + + std::deque service_call_queue_; + bool service_call_in_progress_; + }; } diff --git a/ecal/service/ecal_service/src/log_defs.h b/ecal/service/ecal_service/src/log_defs.h index 1b48d85905..d1c470e99a 100644 --- a/ecal/service/ecal_service/src/log_defs.h +++ b/ecal/service/ecal_service/src/log_defs.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -65,7 +65,7 @@ // This lets the compiler better optimize the code. // #if ECAL_SERVICE_LOG_DEBUG_ENABLED - #define ECAL_SERVICE_LOG_DEBUG(logger, msg) logger(eCAL::service::LogLevel::Debug, msg) + #define ECAL_SERVICE_LOG_DEBUG(logger, msg) logger(ecal_service::LogLevel::Debug, msg) #else #define ECAL_SERVICE_LOG_DEBUG(...) /**/ #endif @@ -75,7 +75,7 @@ // This lets the compiler better optimize the code. // #if ECAL_SERVICE_LOG_DEBUG_VERBOSE_ENABLED - #define ECAL_SERVICE_LOG_DEBUG_VERBOSE(logger,msg) do { logger(eCAL::service::LogLevel::DebugVerbose, msg); } while (0) + #define ECAL_SERVICE_LOG_DEBUG_VERBOSE(logger,msg) do { logger(ecal_service::LogLevel::DebugVerbose, msg); } while (0) #else #define ECAL_SERVICE_LOG_DEBUG_VERBOSE(...) /**/ #endif diff --git a/ecal/service/ecal_service/src/log_helpers.h b/ecal/service/ecal_service/src/log_helpers.h index 9dda632662..04bdfe4710 100644 --- a/ecal/service/ecal_service/src/log_helpers.h +++ b/ecal/service/ecal_service/src/log_helpers.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ===== ============================ * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,46 +22,43 @@ #include #include -namespace eCAL +namespace ecal_service { - namespace service + // Forward declarations + inline std::string get_connection_info_string(const asio::ip::tcp::socket& socket); + inline std::string endpoint_to_string(const asio::ip::tcp::endpoint& endpoint); + + inline std::string get_connection_info_string(const asio::ip::tcp::socket& socket) { - // Forward declarations - inline std::string get_connection_info_string(const asio::ip::tcp::socket& socket); - inline std::string endpoint_to_string(const asio::ip::tcp::endpoint& endpoint); + std::string local_endpoint_string = "???"; + std::string remote_endpoint_string = "???"; - inline std::string get_connection_info_string(const asio::ip::tcp::socket& socket) + // Form local endpoint string { - std::string local_endpoint_string = "???"; - std::string remote_endpoint_string = "???"; - - // Form local endpoint string - { - asio::error_code ec; - const auto endpoint = socket.local_endpoint(ec); - if (!ec) - local_endpoint_string = endpoint_to_string(endpoint); - } - - // form remote endpoint string - { - asio::error_code ec; - const auto endpoint = socket.remote_endpoint(ec); - if (!ec) - remote_endpoint_string = endpoint_to_string(endpoint); - } - - return local_endpoint_string + " -> " + remote_endpoint_string; + asio::error_code ec; + const auto endpoint = socket.local_endpoint(ec); + if (!ec) + local_endpoint_string = endpoint_to_string(endpoint); } - inline std::string endpoint_to_string(const asio::ip::tcp::endpoint& endpoint) + // form remote endpoint string { asio::error_code ec; - const std::string address_string = endpoint.address().to_string(ec); + const auto endpoint = socket.remote_endpoint(ec); if (!ec) - return address_string + ":" + std::to_string(endpoint.port()); - else - return "???"; + remote_endpoint_string = endpoint_to_string(endpoint); } - } // namespace service -}// namespace eCAL + + return local_endpoint_string + " -> " + remote_endpoint_string; + } + + inline std::string endpoint_to_string(const asio::ip::tcp::endpoint& endpoint) + { + asio::error_code ec; + const std::string address_string = endpoint.address().to_string(ec); + if (!ec) + return address_string + ":" + std::to_string(endpoint.port()); + else + return "???"; + } +}// namespace ecal_service diff --git a/ecal/service/ecal_service/src/protocol_layout.h b/ecal/service/ecal_service/src/protocol_layout.h index 3197e05da3..644005caf1 100644 --- a/ecal/service/ecal_service/src/protocol_layout.h +++ b/ecal/service/ecal_service/src/protocol_layout.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,53 +21,50 @@ #include -namespace eCAL +namespace ecal_service { - namespace service + // Message type used since protocol version 1 + enum class MessageType: std::uint8_t { - // Message type used since protocol version 1 - enum class MessageType: std::uint8_t - { - Undefined = 0, - ProtocolHandshakeRequest = 1, - ProtocolHandshakeResponse = 2, - ServiceRequest = 3, - ServiceResponse = 4, - }; + Undefined = 0, + ProtocolHandshakeRequest = 1, + ProtocolHandshakeResponse = 2, + ServiceRequest = 3, + ServiceResponse = 4, + }; #pragma pack(push, 1) - struct TcpHeaderV0 - { - std::uint32_t package_size_n = 0; // package size in network byte order - std::uint32_t reserved1 = 0; // reserved - std::uint64_t reserved2 = 0; // reserved - }; + struct TcpHeaderV0 + { + std::uint32_t package_size_n = 0; // package size in network byte order + std::uint32_t reserved1 = 0; // reserved + std::uint64_t reserved2 = 0; // reserved + }; - // TCP Header - // - Used for service request since protocol version 1 - // - Used for response since protocol version 0 - struct TcpHeaderV1 - { - std::uint32_t package_size_n = 0; // package size in network byte order - std::uint8_t version = 0; // protocol version (since protocol V1 / eCAL 5.12) - MessageType message_type = MessageType::Undefined; // message type (since protocol V1 / eCAL 5.12) - std::uint16_t header_size_n = 0; // header size in network byte order (since protocol V1 / eCAL 5.12) - std::uint64_t reserved = 0; // reserved - }; + // TCP Header + // - Used for service request since protocol version 1 + // - Used for response since protocol version 0 + struct TcpHeaderV1 + { + std::uint32_t package_size_n = 0; // package size in network byte order + std::uint8_t version = 0; // protocol version (since protocol V1 / eCAL 5.12) + MessageType message_type = MessageType::Undefined; // message type (since protocol V1 / eCAL 5.12) + std::uint16_t header_size_n = 0; // header size in network byte order (since protocol V1 / eCAL 5.12) + std::uint64_t reserved = 0; // reserved + }; - // Handshake Request Message, since protocol v1 - struct ProtocolHandshakeRequestMessage - { - std::uint8_t min_supported_protocol_version = 0; - std::uint8_t max_supported_protocol_version = 0; - }; + // Handshake Request Message, since protocol v1 + struct ProtocolHandshakeRequestMessage + { + std::uint8_t min_supported_protocol_version = 0; + std::uint8_t max_supported_protocol_version = 0; + }; - // Handshake Response Message, since protocol v1 - struct ProtocolHandshakeResponseMessage - { - std::uint8_t accepted_protocol_version = 0; - }; + // Handshake Response Message, since protocol v1 + struct ProtocolHandshakeResponseMessage + { + std::uint8_t accepted_protocol_version = 0; + }; #pragma pack(pop) - } // namespace service -} // namespace eCAL +} // namespace ecal_service diff --git a/ecal/service/ecal_service/src/protocol_v1.cpp b/ecal/service/ecal_service/src/protocol_v1.cpp index 7be282cbe7..b9452fb419 100644 --- a/ecal/service/ecal_service/src/protocol_v1.cpp +++ b/ecal/service/ecal_service/src/protocol_v1.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,171 +35,168 @@ #include #endif -namespace eCAL +namespace ecal_service { - namespace service + namespace ProtocolV1 { - namespace ProtocolV1 + namespace { - namespace + void read_header_start(asio::ip::tcp::socket& socket, std::mutex& socket_mutex, const ErrorCallbackT& error_cb, const ReceiveSuccessCallback& success_cb); + void read_header_rest(asio::ip::tcp::socket& socket, std::mutex& socket_mutex, const std::shared_ptr>& header_buffer, size_t bytes_already_read, const ErrorCallbackT& error_cb, const ReceiveSuccessCallback& success_cb); + void read_payload(asio::ip::tcp::socket& socket, std::mutex& socket_mutex, const std::shared_ptr>& header_buffer, const ErrorCallbackT& error_cb, const ReceiveSuccessCallback& success_cb); + + /////////////////////////////////////////////////// + // Read and write implementation + /////////////////////////////////////////////////// + void read_header_start(asio::ip::tcp::socket& socket, std::mutex& socket_mutex, const ErrorCallbackT& error_cb, const ReceiveSuccessCallback& success_cb) { - void read_header_start(asio::ip::tcp::socket& socket, std::mutex& socket_mutex, const ErrorCallbackT& error_cb, const ReceiveSuccessCallback& success_cb); - void read_header_rest(asio::ip::tcp::socket& socket, std::mutex& socket_mutex, const std::shared_ptr>& header_buffer, size_t bytes_already_read, const ErrorCallbackT& error_cb, const ReceiveSuccessCallback& success_cb); - void read_payload(asio::ip::tcp::socket& socket, std::mutex& socket_mutex, const std::shared_ptr>& header_buffer, const ErrorCallbackT& error_cb, const ReceiveSuccessCallback& success_cb); - - /////////////////////////////////////////////////// - // Read and write implementation - /////////////////////////////////////////////////// - void read_header_start(asio::ip::tcp::socket& socket, std::mutex& socket_mutex, const ErrorCallbackT& error_cb, const ReceiveSuccessCallback& success_cb) - { - // Get size of the entire header as it is currently known. What comes from - // the network may be larger or smaller. - constexpr size_t header_size = sizeof(eCAL::service::TcpHeaderV1); - - // We read the first 8 bytes of the header first. The header does not start - // with the header_size, but it contains it at byte 7+8, which is why we - // read the first 8 bytes here, do determine the header size. - constexpr size_t bytes_to_read_now = 8; - - // Allocate a buffer for the header as we know it. We can make it larger - // later, if necessary. We zero the buffer. - const std::shared_ptr> header_buffer = std::make_shared>(header_size, '\0'); - - // Receive data from the socket: - // - Maximum "bytes_to_read_now" - // - At least "bytes_to_read_now" - // => We read exactly the "bytes_to_read_now" amount of bytes - const std::lock_guard socket_lock(socket_mutex); - asio::async_read(socket - , asio::buffer(header_buffer->data(), bytes_to_read_now) - , asio::transfer_at_least(bytes_to_read_now) - , [&socket, &socket_mutex, header_buffer, error_cb, success_cb](asio::error_code ec, std::size_t bytes_read) + // Get size of the entire header as it is currently known. What comes from + // the network may be larger or smaller. + constexpr size_t header_size = sizeof(ecal_service::TcpHeaderV1); + + // We read the first 8 bytes of the header first. The header does not start + // with the header_size, but it contains it at byte 7+8, which is why we + // read the first 8 bytes here, do determine the header size. + constexpr size_t bytes_to_read_now = 8; + + // Allocate a buffer for the header as we know it. We can make it larger + // later, if necessary. We zero the buffer. + const std::shared_ptr> header_buffer = std::make_shared>(header_size, '\0'); + + // Receive data from the socket: + // - Maximum "bytes_to_read_now" + // - At least "bytes_to_read_now" + // => We read exactly the "bytes_to_read_now" amount of bytes + const std::lock_guard socket_lock(socket_mutex); + asio::async_read(socket + , asio::buffer(header_buffer->data(), bytes_to_read_now) + , asio::transfer_at_least(bytes_to_read_now) + , [&socket, &socket_mutex, header_buffer, error_cb, success_cb](asio::error_code ec, std::size_t bytes_read) + { + if (ec) { - if (ec) - { - // Call error callback - error_cb(ec); - return; - } - - // Read the rest of the header! - read_header_rest(socket, socket_mutex, header_buffer, bytes_read, error_cb, success_cb); - }); - } + // Call error callback + error_cb(ec); + return; + } + + // Read the rest of the header! + read_header_rest(socket, socket_mutex, header_buffer, bytes_read, error_cb, success_cb); + }); + } - void read_header_rest(asio::ip::tcp::socket& socket, std::mutex& socket_mutex, const std::shared_ptr>& header_buffer, size_t bytes_already_read, const ErrorCallbackT& error_cb, const ReceiveSuccessCallback& success_cb) + void read_header_rest(asio::ip::tcp::socket& socket, std::mutex& socket_mutex, const std::shared_ptr>& header_buffer, size_t bytes_already_read, const ErrorCallbackT& error_cb, const ReceiveSuccessCallback& success_cb) + { + // Check how big the remote header claims to be + const size_t remote_header_size = ntohs(reinterpret_cast(header_buffer->data())->header_size_n); + + // Resize the header buffer if necessary. We will not be able to use those + // bytes, as we don't know what they mean, but we must receive them anyways. + if (remote_header_size > header_buffer->size()) { - // Check how big the remote header claims to be - const size_t remote_header_size = ntohs(reinterpret_cast(header_buffer->data())->header_size_n); - - // Resize the header buffer if necessary. We will not be able to use those - // bytes, as we don't know what they mean, but we must receive them anyways. - if (remote_header_size > header_buffer->size()) - { - header_buffer->resize(remote_header_size, '\0'); - } - - // Calculate how many bytes we still need to read until we have received the - // entire header - const size_t bytes_still_to_read = header_buffer->size() - bytes_already_read; - - // If the header is finished, we directly go over to reading the payload - // Note: This should actually never happen, as after the already read - // 8 bytes should come at least 8 reserved bytes. - if (bytes_still_to_read <= 0) - { - read_payload(socket, socket_mutex, header_buffer, error_cb, success_cb); - return; - } - - // Read the remaining bytes from the header - const std::lock_guard socket_lock(socket_mutex); - asio::async_read(socket - , asio::buffer(&((*header_buffer)[bytes_already_read]), bytes_still_to_read) - , asio::transfer_at_least(bytes_still_to_read) - , [&socket, &socket_mutex, header_buffer, error_cb, success_cb](asio::error_code ec, std::size_t /*bytes_read*/) - { - if (ec) - { - // Call callback - error_cb(ec); - return; - } - - // Start reading the payload! - const uint32_t payload_size = ntohl(reinterpret_cast(header_buffer->data())->package_size_n); - - if (payload_size > 0) - { - // If there is a payload, read it - read_payload(socket, socket_mutex, header_buffer, error_cb, success_cb); - } - else - { - // If there is no payload, directly execute the callback with an empty string - success_cb(header_buffer, std::make_shared()); - } - }); + header_buffer->resize(remote_header_size, '\0'); } - void read_payload(asio::ip::tcp::socket& socket, std::mutex& socket_mutex, const std::shared_ptr>& header_buffer, const ErrorCallbackT& error_cb, const ReceiveSuccessCallback& success_cb) + // Calculate how many bytes we still need to read until we have received the + // entire header + const size_t bytes_still_to_read = header_buffer->size() - bytes_already_read; + + // If the header is finished, we directly go over to reading the payload + // Note: This should actually never happen, as after the already read + // 8 bytes should come at least 8 reserved bytes. + if (bytes_still_to_read <= 0) { - // Read how many bytes we will get as payload - const uint32_t payload_size = ntohl(reinterpret_cast(header_buffer->data())->package_size_n); - - // Reserver enough memory for receiving the entire payload. The payload is - // represented as an std::string for legacy, reasons. It is not textual data. - const std::shared_ptr payload_buffer = std::make_shared(payload_size, '\0'); - - // Read all the payload data into the payload_buffer - const std::lock_guard socket_lock(socket_mutex); - asio::async_read(socket - , asio::buffer(const_cast(payload_buffer->data()), payload_buffer->size()) - , asio::transfer_at_least(payload_buffer->size()) - , [header_buffer, payload_buffer, error_cb, success_cb](asio::error_code ec, std::size_t /*bytes_read*/) + read_payload(socket, socket_mutex, header_buffer, error_cb, success_cb); + return; + } + + // Read the remaining bytes from the header + const std::lock_guard socket_lock(socket_mutex); + asio::async_read(socket + , asio::buffer(&((*header_buffer)[bytes_already_read]), bytes_still_to_read) + , asio::transfer_at_least(bytes_still_to_read) + , [&socket, &socket_mutex, header_buffer, error_cb, success_cb](asio::error_code ec, std::size_t /*bytes_read*/) + { + if (ec) { - if (ec) - { - // Call error callback - error_cb(ec); - return; - } - - // Call success callback - success_cb(header_buffer, payload_buffer); - }); + // Call callback + error_cb(ec); + return; + } - } + // Start reading the payload! + const uint32_t payload_size = ntohl(reinterpret_cast(header_buffer->data())->package_size_n); + + if (payload_size > 0) + { + // If there is a payload, read it + read_payload(socket, socket_mutex, header_buffer, error_cb, success_cb); + } + else + { + // If there is no payload, directly execute the callback with an empty string + success_cb(header_buffer, std::make_shared()); + } + }); } - /////////////////////////////////////////////////// - // Public API - /////////////////////////////////////////////////// - void async_send_payload (asio::ip::tcp::socket& socket, std::mutex& socket_mutex, const std::shared_ptr& header_buffer, const std::shared_ptr& payload_buffer, const ErrorCallbackT& error_cb, const SendSuccessCallback& success_cb) - { - const std::vector buffer_list { asio::buffer(reinterpret_cast(header_buffer.get()), sizeof(eCAL::service::TcpHeaderV1)) - , asio::buffer(*payload_buffer)}; + void read_payload(asio::ip::tcp::socket& socket, std::mutex& socket_mutex, const std::shared_ptr>& header_buffer, const ErrorCallbackT& error_cb, const ReceiveSuccessCallback& success_cb) + { + // Read how many bytes we will get as payload + const uint32_t payload_size = ntohl(reinterpret_cast(header_buffer->data())->package_size_n); + // Reserver enough memory for receiving the entire payload. The payload is + // represented as an std::string for legacy, reasons. It is not textual data. + const std::shared_ptr payload_buffer = std::make_shared(payload_size, '\0'); + + // Read all the payload data into the payload_buffer const std::lock_guard socket_lock(socket_mutex); - asio::async_write(socket - , buffer_list - , [header_buffer, payload_buffer, error_cb, success_cb](asio::error_code ec, std::size_t /*bytes_sent*/) + asio::async_read(socket + , asio::buffer(const_cast(payload_buffer->data()), payload_buffer->size()) + , asio::transfer_at_least(payload_buffer->size()) + , [header_buffer, payload_buffer, error_cb, success_cb](asio::error_code ec, std::size_t /*bytes_read*/) + { + if (ec) { - if (ec) - { - // Call error callback - error_cb(ec); - return; - } - success_cb(); - }); + // Call error callback + error_cb(ec); + return; + } + + // Call success callback + success_cb(header_buffer, payload_buffer); + }); } + } + + /////////////////////////////////////////////////// + // Public API + /////////////////////////////////////////////////// + void async_send_payload (asio::ip::tcp::socket& socket, std::mutex& socket_mutex, const std::shared_ptr& header_buffer, const std::shared_ptr& payload_buffer, const ErrorCallbackT& error_cb, const SendSuccessCallback& success_cb) + { + const std::vector buffer_list { asio::buffer(reinterpret_cast(header_buffer.get()), sizeof(ecal_service::TcpHeaderV1)) + , asio::buffer(*payload_buffer)}; + + const std::lock_guard socket_lock(socket_mutex); + asio::async_write(socket + , buffer_list + , [header_buffer, payload_buffer, error_cb, success_cb](asio::error_code ec, std::size_t /*bytes_sent*/) + { + if (ec) + { + // Call error callback + error_cb(ec); + return; + } + success_cb(); + }); - void async_receive_payload(asio::ip::tcp::socket& socket, std::mutex& socket_mutex, const ErrorCallbackT& error_cb, const ReceiveSuccessCallback& success_cb) - { - read_header_start(socket, socket_mutex, error_cb, success_cb); - } - } // namespace ProtocolV1 - } // namespace service -} // namespace eCAL + } + + void async_receive_payload(asio::ip::tcp::socket& socket, std::mutex& socket_mutex, const ErrorCallbackT& error_cb, const ReceiveSuccessCallback& success_cb) + { + read_header_start(socket, socket_mutex, error_cb, success_cb); + } + } // namespace ProtocolV1 +} // namespace ecal_service diff --git a/ecal/service/ecal_service/src/protocol_v1.h b/ecal/service/ecal_service/src/protocol_v1.h index 025a6fe4db..d0f32f0542 100644 --- a/ecal/service/ecal_service/src/protocol_v1.h +++ b/ecal/service/ecal_service/src/protocol_v1.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ===== ============================ * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,18 +29,15 @@ #include "protocol_layout.h" -namespace eCAL +namespace ecal_service { - namespace service + namespace ProtocolV1 { - namespace ProtocolV1 - { - using ErrorCallbackT = std::function; - using SendSuccessCallback = std::function; - using ReceiveSuccessCallback = std::function>& header_buffer, const std::shared_ptr& payload_buffer)>; + using ErrorCallbackT = std::function; + using SendSuccessCallback = std::function; + using ReceiveSuccessCallback = std::function>& header_buffer, const std::shared_ptr& payload_buffer)>; - void async_send_payload (asio::ip::tcp::socket& socket, std::mutex& socket_mutex, const std::shared_ptr& header_buffer, const std::shared_ptr& payload_buffer, const ErrorCallbackT& error_cb, const SendSuccessCallback& success_cb); - void async_receive_payload(asio::ip::tcp::socket& socket, std::mutex& socket_mutex, const ErrorCallbackT& error_cb, const ReceiveSuccessCallback& success_cb); - } + void async_send_payload (asio::ip::tcp::socket& socket, std::mutex& socket_mutex, const std::shared_ptr& header_buffer, const std::shared_ptr& payload_buffer, const ErrorCallbackT& error_cb, const SendSuccessCallback& success_cb); + void async_receive_payload(asio::ip::tcp::socket& socket, std::mutex& socket_mutex, const ErrorCallbackT& error_cb, const ReceiveSuccessCallback& success_cb); } } diff --git a/ecal/service/ecal_service/src/server.cpp b/ecal/service/ecal_service/src/server.cpp index 7e6c726d3c..3cc0d5004a 100644 --- a/ecal/service/ecal_service/src/server.cpp +++ b/ecal/service/ecal_service/src/server.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,83 +17,80 @@ * ========================= eCAL LICENSE ================================= */ -#include +#include #include #include #include -#include +#include #include "server_impl.h" -namespace eCAL +namespace ecal_service { - namespace service + /////////////////////////////////////////// + // Constructor, Destructor, Create + /////////////////////////////////////////// + std::shared_ptr Server::create(const std::shared_ptr& io_context + , std::uint8_t protocol_version + , std::uint16_t port + , const ServiceCallbackT& service_callback + , bool parallel_service_calls_enabled + , const EventCallbackT& event_callback + , const LoggerT& logger + , const DeleteCallbackT& delete_callback) { - /////////////////////////////////////////// - // Constructor, Destructor, Create - /////////////////////////////////////////// - std::shared_ptr Server::create(const std::shared_ptr& io_context - , std::uint8_t protocol_version - , std::uint16_t port - , const ServiceCallbackT& service_callback - , bool parallel_service_calls_enabled - , const EventCallbackT& event_callback - , const LoggerT& logger - , const DeleteCallbackT& delete_callback) + auto deleter = [delete_callback](Server* server) { - auto deleter = [delete_callback](Server* server) - { - delete_callback(server); - delete server; // NOLINT(cppcoreguidelines-owning-memory) - }; + delete_callback(server); + delete server; // NOLINT(cppcoreguidelines-owning-memory) + }; - return std::shared_ptr(new Server(io_context, protocol_version, port, service_callback, parallel_service_calls_enabled, event_callback, logger), deleter); - } + return std::shared_ptr(new Server(io_context, protocol_version, port, service_callback, parallel_service_calls_enabled, event_callback, logger), deleter); + } - std::shared_ptr Server::create(const std::shared_ptr& io_context - , std::uint8_t protocol_version - , std::uint16_t port - , const ServiceCallbackT& service_callback - , bool parallel_service_calls_enabled - , const EventCallbackT& event_callback - , const LoggerT& logger) - { - return std::shared_ptr(new Server(io_context, protocol_version, port, service_callback, parallel_service_calls_enabled, event_callback, logger)); - } + std::shared_ptr Server::create(const std::shared_ptr& io_context + , std::uint8_t protocol_version + , std::uint16_t port + , const ServiceCallbackT& service_callback + , bool parallel_service_calls_enabled + , const EventCallbackT& event_callback + , const LoggerT& logger) + { + return std::shared_ptr(new Server(io_context, protocol_version, port, service_callback, parallel_service_calls_enabled, event_callback, logger)); + } - std::shared_ptr Server::create(const std::shared_ptr& io_context - , std::uint8_t protocol_version - , std::uint16_t port - , const ServiceCallbackT& service_callback - , bool parallel_service_calls_enabled - , const EventCallbackT& event_callback - , const DeleteCallbackT& delete_callback) - { - return Server::create(io_context, protocol_version, port, service_callback, parallel_service_calls_enabled, event_callback, default_logger("Service Server"), delete_callback); - } + std::shared_ptr Server::create(const std::shared_ptr& io_context + , std::uint8_t protocol_version + , std::uint16_t port + , const ServiceCallbackT& service_callback + , bool parallel_service_calls_enabled + , const EventCallbackT& event_callback + , const DeleteCallbackT& delete_callback) + { + return Server::create(io_context, protocol_version, port, service_callback, parallel_service_calls_enabled, event_callback, default_logger("Service Server"), delete_callback); + } - Server::Server(const std::shared_ptr& io_context - , std::uint8_t protocol_version - , std::uint16_t port - , const ServiceCallbackT& service_callback - , bool parallel_service_calls_enabled - , const EventCallbackT& event_callback - , const LoggerT& logger) - { - impl_ = ServerImpl::create(io_context, protocol_version, port, service_callback, parallel_service_calls_enabled, event_callback, logger); - } + Server::Server(const std::shared_ptr& io_context + , std::uint8_t protocol_version + , std::uint16_t port + , const ServiceCallbackT& service_callback + , bool parallel_service_calls_enabled + , const EventCallbackT& event_callback + , const LoggerT& logger) + { + impl_ = ServerImpl::create(io_context, protocol_version, port, service_callback, parallel_service_calls_enabled, event_callback, logger); + } + + /////////////////////////////////////////// + // API + /////////////////////////////////////////// - /////////////////////////////////////////// - // API - /////////////////////////////////////////// - - bool Server::is_connected() const { return impl_->is_connected(); } - int Server::get_connection_count() const { return impl_->get_connection_count(); } - std::uint16_t Server::get_port() const { return impl_->get_port(); } - void Server::stop() { impl_->stop(); } + bool Server::is_connected() const { return impl_->is_connected(); } + int Server::get_connection_count() const { return impl_->get_connection_count(); } + std::uint16_t Server::get_port() const { return impl_->get_port(); } + void Server::stop() { impl_->stop(); } - } // namespace service -} // namespace eCAL +} // namespace ecal_service diff --git a/ecal/service/ecal_service/src/server_impl.cpp b/ecal/service/ecal_service/src/server_impl.cpp index 9566e4ec07..4e46baf131 100644 --- a/ecal/service/ecal_service/src/server_impl.cpp +++ b/ecal/service/ecal_service/src/server_impl.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2024 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,287 +29,284 @@ #include "server_session_impl_base.h" #include "server_session_impl_v1.h" -#include -#include -#include +#include +#include +#include #include "log_defs.h" -namespace eCAL +namespace ecal_service { - namespace service + /////////////////////////////////////////// + // Constructor, Destructor, Create + /////////////////////////////////////////// + + std::shared_ptr ServerImpl::create(const std::shared_ptr& io_context + , std::uint8_t protocol_version + , std::uint16_t port + , const ServerServiceCallbackT& service_callback // TODO: The service callback may block a long time. This may cause the entire network stack to wait for long running service callbacks. Maybe it is a good idea to have some kind of "future" object, that the user can hand to some differen io_context or to a custom thread. That thread will then work on the object and call some function / let it go out of scope, which will then trigger sending the response to the client. + , bool parallel_service_calls_enabled + , const ServerEventCallbackT& event_callback + , const LoggerT& logger) { - /////////////////////////////////////////// - // Constructor, Destructor, Create - /////////////////////////////////////////// - - std::shared_ptr ServerImpl::create(const std::shared_ptr& io_context - , std::uint8_t protocol_version - , std::uint16_t port - , const ServerServiceCallbackT& service_callback // TODO: The service callback may block a long time. This may cause the entire network stack to wait for long running service callbacks. Maybe it is a good idea to have some kind of "future" object, that the user can hand to some differen io_context or to a custom thread. That thread will then work on the object and call some function / let it go out of scope, which will then trigger sending the response to the client. - , bool parallel_service_calls_enabled - , const ServerEventCallbackT& event_callback - , const LoggerT& logger) - { - // Create a new instance with the protected constructor - // Note: make_shared not possible, because constructor is protected - auto instance = std::shared_ptr(new ServerImpl(io_context, service_callback, parallel_service_calls_enabled, event_callback, logger)); + // Create a new instance with the protected constructor + // Note: make_shared not possible, because constructor is protected + auto instance = std::shared_ptr(new ServerImpl(io_context, service_callback, parallel_service_calls_enabled, event_callback, logger)); + + // Directly Start accepting new connections + instance->start_accept(protocol_version, port); + + // Return the created and started instance + return instance; + } + + ServerImpl::ServerImpl(const std::shared_ptr& io_context + , const ServerServiceCallbackT& service_callback + , bool parallel_service_calls_enabled + , const ServerEventCallbackT& event_callback + , const LoggerT& logger) + : io_context_ (io_context) + , acceptor_ (*io_context) + , parallel_service_calls_enabled_(parallel_service_calls_enabled) + , service_callback_common_strand_(std::make_shared(*io_context)) + , service_callback_ (service_callback) + , event_callback_ (event_callback) + , logger_ (logger) + { + ECAL_SERVICE_LOG_DEBUG_VERBOSE(logger_, "Service Created"); + } + + ServerImpl::~ServerImpl() + { + stop(); - // Directly Start accepting new connections - instance->start_accept(protocol_version, port); + ECAL_SERVICE_LOG_DEBUG_VERBOSE(logger_, "Service Deleted"); + } - // Return the created and started instance - return instance; - } + /////////////////////////////////////////// + // API + /////////////////////////////////////////// + + bool ServerImpl::is_connected() const + { + return get_connection_count() > 0; + } - ServerImpl::ServerImpl(const std::shared_ptr& io_context - , const ServerServiceCallbackT& service_callback - , bool parallel_service_calls_enabled - , const ServerEventCallbackT& event_callback - , const LoggerT& logger) - : io_context_ (io_context) - , acceptor_ (*io_context) - , parallel_service_calls_enabled_(parallel_service_calls_enabled) - , service_callback_common_strand_(std::make_shared(*io_context)) - , service_callback_ (service_callback) - , event_callback_ (event_callback) - , logger_ (logger) + int ServerImpl::get_connection_count() const + { + const std::lock_guard session_list_lock(session_list_mutex_); + int connection_count = 0; + + // Iterate over all sessions and count the ones that are still alive + for (const auto& session : session_list_) { - ECAL_SERVICE_LOG_DEBUG_VERBOSE(logger_, "Service Created"); + auto session_ptr = session.lock(); + if (session_ptr && (session_ptr->get_state() != ecal_service::State::FAILED)) + { + ++connection_count; + } } - ServerImpl::~ServerImpl() - { - stop(); + return connection_count; + } - ECAL_SERVICE_LOG_DEBUG_VERBOSE(logger_, "Service Deleted"); - } + std::uint16_t ServerImpl::get_port() const + { + asio::error_code ec; - /////////////////////////////////////////// - // API - /////////////////////////////////////////// + const std::lock_guard acceptor_lock(acceptor_mutex_); - bool ServerImpl::is_connected() const + auto endpoint = acceptor_.local_endpoint(ec); + if (!ec) { - return get_connection_count() > 0; + return endpoint.port(); } - - int ServerImpl::get_connection_count() const + else { - const std::lock_guard session_list_lock(session_list_mutex_); - int connection_count = 0; - - // Iterate over all sessions and count the ones that are still alive - for (const auto& session : session_list_) - { - auto session_ptr = session.lock(); - if (session_ptr && (session_ptr->get_state() != eCAL::service::State::FAILED)) - { - ++connection_count; - } - } - - return connection_count; + return 0; } + } + + void ServerImpl::start_accept(std::uint8_t protocol_version, std::uint16_t port) + { + ECAL_SERVICE_LOG_DEBUG(logger_, "Service starting to accept new connections..."); - std::uint16_t ServerImpl::get_port() const + // set up the acceptor to listen on the tcp port + + const asio::ip::tcp::endpoint endpoint(asio::ip::address_v6(), port); + + ECAL_SERVICE_LOG_DEBUG_VERBOSE(logger_, "Service Server: Opening acceptor..."); { asio::error_code ec; - const std::lock_guard acceptor_lock(acceptor_mutex_); - - auto endpoint = acceptor_.local_endpoint(ec); - if (!ec) { - return endpoint.port(); + const std::lock_guard acceptor_lock(acceptor_mutex_); + acceptor_.open(endpoint.protocol(), ec); // NOLINT(bugprone-unused-return-value) -> We already get the return value rom the ec parameter } - else + if (ec) { - return 0; + logger_(ecal_service::LogLevel::Error, "Service Server: Error opening acceptor:" + ec.message()); + // return false; What do do here? } } - void ServerImpl::start_accept(std::uint8_t protocol_version, std::uint16_t port) - { - ECAL_SERVICE_LOG_DEBUG(logger_, "Service starting to accept new connections..."); + ECAL_SERVICE_LOG_DEBUG_VERBOSE(logger_, "Service Server: Setting \"reuse_address\" option..."); - // set up the acceptor to listen on the tcp port - const asio::ip::tcp::endpoint endpoint(asio::ip::address_v6(), port); - - ECAL_SERVICE_LOG_DEBUG_VERBOSE(logger_, "Service Server: Opening acceptor..."); + { + asio::error_code ec; { - asio::error_code ec; - - { - const std::lock_guard acceptor_lock(acceptor_mutex_); - acceptor_.open(endpoint.protocol(), ec); // NOLINT(bugprone-unused-return-value) -> We already get the return value rom the ec parameter - } - if (ec) - { - logger_(eCAL::service::LogLevel::Error, "Service Server: Error opening acceptor:" + ec.message()); - // return false; What do do here? - } + acceptor_.set_option(asio::ip::tcp::acceptor::reuse_address(true), ec); // NOLINT(bugprone-unused-return-value) -> We already get the value from the ec parameter + const std::lock_guard acceptor_lock(acceptor_mutex_); } - - ECAL_SERVICE_LOG_DEBUG_VERBOSE(logger_, "Service Server: Setting \"reuse_address\" option..."); - - + if (ec) { - asio::error_code ec; - { - acceptor_.set_option(asio::ip::tcp::acceptor::reuse_address(true), ec); // NOLINT(bugprone-unused-return-value) -> We already get the value from the ec parameter - const std::lock_guard acceptor_lock(acceptor_mutex_); - } - if (ec) - { - logger_(eCAL::service::LogLevel::Error, "Service Server: Error setting \"reuse_address\" option:" + ec.message()); - // return false; What do do here? - } + logger_(ecal_service::LogLevel::Error, "Service Server: Error setting \"reuse_address\" option:" + ec.message()); + // return false; What do do here? } + } - ECAL_SERVICE_LOG_DEBUG_VERBOSE(logger_, "Service Server: Binding acceptor to endpoint..."); + ECAL_SERVICE_LOG_DEBUG_VERBOSE(logger_, "Service Server: Binding acceptor to endpoint..."); + { + asio::error_code ec; { - asio::error_code ec; - { - const std::lock_guard acceptor_lock(acceptor_mutex_); - acceptor_.bind(endpoint, ec); // NOLINT(bugprone-unused-return-value) -> We already get the return value rom the ec parameter - } - if (ec) - { - logger_(eCAL::service::LogLevel::Error, "Service Server: Error binding acceptor:" + ec.message()); - // return false; What do do here? - } + const std::lock_guard acceptor_lock(acceptor_mutex_); + acceptor_.bind(endpoint, ec); // NOLINT(bugprone-unused-return-value) -> We already get the return value rom the ec parameter } - - ECAL_SERVICE_LOG_DEBUG_VERBOSE(logger_, "Service Server: Listening on acceptor..."); - + if (ec) { - asio::error_code ec; - { - const std::lock_guard acceptor_lock(acceptor_mutex_); - acceptor_.listen(asio::socket_base::max_listen_connections, ec); // NOLINT(bugprone-unused-return-value) -> We already get the return value rom the ec parameter - } - if (ec) - { - logger_(eCAL::service::LogLevel::Error, "Service Server: Error listening on acceptor: " + ec.message()); - // return false; What do do here? - } + logger_(ecal_service::LogLevel::Error, "Service Server: Error binding acceptor:" + ec.message()); + // return false; What do do here? } - - wait_for_next_client(protocol_version); } - void ServerImpl::wait_for_next_client(std::uint8_t protocol_version) - { - ECAL_SERVICE_LOG_DEBUG_VERBOSE(logger_, "Service waiting for next client..."); + ECAL_SERVICE_LOG_DEBUG_VERBOSE(logger_, "Service Server: Listening on acceptor..."); - const eCAL::service::ServerSessionBase::ShutdownCallbackT shutdown_callback - = [weak_me = std::weak_ptr(shared_from_this())](const std::shared_ptr& session_to_remove) -> void - { - // Create a shared_ptr to the class. If it doesn't exist - // anymore, we will get a nullpointer. In that case, we cannot - // execute the callback. - const std::shared_ptr me = weak_me.lock(); - if (me) - { - const std::lock_guard session_list_lock(me->session_list_mutex_); - - // Remove the session from the session list - const auto session_it = std::find_if(me->session_list_.begin(), me->session_list_.end() - , [session_to_remove](const auto& existing_session) { return session_to_remove == existing_session.lock(); }); - if (session_it != me->session_list_.end()) - { - me->session_list_.erase(session_it); - } - } - }; - - std::shared_ptr new_session; - - std::shared_ptr service_callback_strand; - if (parallel_service_calls_enabled_) + { + asio::error_code ec; { - service_callback_strand = std::make_shared(*io_context_); + const std::lock_guard acceptor_lock(acceptor_mutex_); + acceptor_.listen(asio::socket_base::max_listen_connections, ec); // NOLINT(bugprone-unused-return-value) -> We already get the return value rom the ec parameter } - else + if (ec) { - service_callback_strand = service_callback_common_strand_; + logger_(ecal_service::LogLevel::Error, "Service Server: Error listening on acceptor: " + ec.message()); + // return false; What do do here? } + } - // we support v1 protocol only - new_session = eCAL::service::ServerSessionV1::create(io_context_, service_callback_, service_callback_strand, event_callback_, shutdown_callback, logger_); + wait_for_next_client(protocol_version); + } - // Accept new session. - // By only storing a weak_ptr to this, we assure that the user can still - // delete the service from the outside. - const std::lock_guard acceptor_lock(acceptor_mutex_); - acceptor_.async_accept(new_session->socket() - , [weak_me = std::weak_ptr(shared_from_this()), new_session, protocol_version, logger_copy = logger_](auto ec) + void ServerImpl::wait_for_next_client(std::uint8_t protocol_version) + { + ECAL_SERVICE_LOG_DEBUG_VERBOSE(logger_, "Service waiting for next client..."); + + const ecal_service::ServerSessionBase::ShutdownCallbackT shutdown_callback + = [weak_me = std::weak_ptr(shared_from_this())](const std::shared_ptr& session_to_remove) -> void + { + // Create a shared_ptr to the class. If it doesn't exist + // anymore, we will get a nullpointer. In that case, we cannot + // execute the callback. + const std::shared_ptr me = weak_me.lock(); + if (me) { - if (ec) + const std::lock_guard session_list_lock(me->session_list_mutex_); + + // Remove the session from the session list + const auto session_it = std::find_if(me->session_list_.begin(), me->session_list_.end() + , [session_to_remove](const auto& existing_session) { return session_to_remove == existing_session.lock(); }); + if (session_it != me->session_list_.end()) { - logger_copy(LogLevel::Info, "Service shutting down: " + ec.message()); - return; + me->session_list_.erase(session_it); } - else - { + } + }; - ECAL_SERVICE_LOG_DEBUG_VERBOSE(logger_copy, "Service client initiated connection..."); + std::shared_ptr new_session; - const std::shared_ptr me = weak_me.lock(); - if (me) - { - // Add the new session to the session list. The session list is a list of weak_ptr. - // Therefore, the session list will not keep the session alive, they will do that themselves. - const std::lock_guard session_list_lock(me->session_list_mutex_); - me->session_list_.push_back(new_session); + std::shared_ptr service_callback_strand; + if (parallel_service_calls_enabled_) + { + service_callback_strand = std::make_shared(*io_context_); + } + else + { + service_callback_strand = service_callback_common_strand_; + } - // Start the new session, that now has a connection - // The session will call the callback and increase the connection count - new_session->start(); - } - } + // we support v1 protocol only + new_session = ecal_service::ServerSessionV1::create(io_context_, service_callback_, service_callback_strand, event_callback_, shutdown_callback, logger_); + + // Accept new session. + // By only storing a weak_ptr to this, we assure that the user can still + // delete the service from the outside. + const std::lock_guard acceptor_lock(acceptor_mutex_); + acceptor_.async_accept(new_session->socket() + , [weak_me = std::weak_ptr(shared_from_this()), new_session, protocol_version, logger_copy = logger_](auto ec) + { + if (ec) + { + logger_copy(LogLevel::Info, "Service shutting down: " + ec.message()); + return; + } + else + { + + ECAL_SERVICE_LOG_DEBUG_VERBOSE(logger_copy, "Service client initiated connection..."); - // Continue creating and accepting the next session const std::shared_ptr me = weak_me.lock(); if (me) { - me->wait_for_next_client(protocol_version); - } - else - { - logger_copy(LogLevel::Info, "Service shutting down."); + // Add the new session to the session list. The session list is a list of weak_ptr. + // Therefore, the session list will not keep the session alive, they will do that themselves. + const std::lock_guard session_list_lock(me->session_list_mutex_); + me->session_list_.push_back(new_session); + + // Start the new session, that now has a connection + // The session will call the callback and increase the connection count + new_session->start(); } - }); + } - } + // Continue creating and accepting the next session + const std::shared_ptr me = weak_me.lock(); + if (me) + { + me->wait_for_next_client(protocol_version); + } + else + { + logger_copy(LogLevel::Info, "Service shutting down."); + } + }); - void ServerImpl::stop() + } + + void ServerImpl::stop() + { { - { - // Lock mutex for making the stop function thread safe - const std::lock_guard acceptor_lock(acceptor_mutex_); + // Lock mutex for making the stop function thread safe + const std::lock_guard acceptor_lock(acceptor_mutex_); - // Close acceptor, if necessary - if (acceptor_.is_open()) - { - asio::error_code ec; - acceptor_.close(ec); // NOLINT(bugprone-unused-return-value) -> We already get the return value rom the ec parameter - } + // Close acceptor, if necessary + if (acceptor_.is_open()) + { + asio::error_code ec; + acceptor_.close(ec); // NOLINT(bugprone-unused-return-value) -> We already get the return value rom the ec parameter } - - // Stop all sessions to clients + } + + // Stop all sessions to clients + { + const std::lock_guard session_list_lock(session_list_mutex_); + for(const auto& session_weak : session_list_) { - const std::lock_guard session_list_lock(session_list_mutex_); - for(const auto& session_weak : session_list_) - { - const auto session = session_weak.lock(); - if (session) - session->stop(); - } + const auto session = session_weak.lock(); + if (session) + session->stop(); } } - } // namespace service -} // namespace eCAL + } +} // namespace ecal_service diff --git a/ecal/service/ecal_service/src/server_impl.h b/ecal/service/ecal_service/src/server_impl.h index 6ef2355d63..6b3c0cda2a 100644 --- a/ecal/service/ecal_service/src/server_impl.h +++ b/ecal/service/ecal_service/src/server_impl.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,80 +34,77 @@ #pragma warning(pop) #endif -#include -#include +#include +#include #include "server_session_impl_base.h" -namespace eCAL +namespace ecal_service { - namespace service + class ServerImpl : public std::enable_shared_from_this { - class ServerImpl : public std::enable_shared_from_this - { - /////////////////////////////////////////// - // Constructor, Destructor, Create - /////////////////////////////////////////// - - public: - static std::shared_ptr create(const std::shared_ptr& io_context - , std::uint8_t protocol_version - , std::uint16_t port - , const ServerServiceCallbackT& service_callback - , bool parallel_service_calls_enabled - , const ServerEventCallbackT& event_callback - , const LoggerT& logger = default_logger("Service Server")); - - protected: - ServerImpl(const std::shared_ptr& io_context - , const ServerServiceCallbackT& service_callback - , bool parallel_service_calls_enabled - , const ServerEventCallbackT& event_callback - , const LoggerT& logger); - - public: - ServerImpl(const ServerImpl&) = delete; // Copy construct - ServerImpl(ServerImpl&&) = delete; // Move construct - - ServerImpl& operator=(const ServerImpl&) = delete; // Copy assign - ServerImpl& operator=(ServerImpl&&) = delete; // Move assign - - ~ServerImpl(); - - /////////////////////////////////////////// - // API - /////////////////////////////////////////// - - public: - bool is_connected() const; - int get_connection_count() const; - std::uint16_t get_port() const; - - void stop(); - - private: - void start_accept(std::uint8_t protocol_version, std::uint16_t port); - void wait_for_next_client(std::uint8_t protocol_version); - - /////////////////////////////////////////// - // Member Variables - /////////////////////////////////////////// - - private: - const std::shared_ptr io_context_; - asio::ip::tcp::acceptor acceptor_; - mutable std::mutex acceptor_mutex_; //!< Mutex for stopping the server. The stop() function is both used externally (via API) and from within the server itself. Closing the acceptor is not thread-safe, so we need to protect it. - - const bool parallel_service_calls_enabled_; - const std::shared_ptr service_callback_common_strand_; - const ServerServiceCallbackT service_callback_; - const ServerEventCallbackT event_callback_; - - mutable std::mutex session_list_mutex_; - std::vector> session_list_; - - const LoggerT logger_; - - }; - } // namespace service -} // namespace eCAL + /////////////////////////////////////////// + // Constructor, Destructor, Create + /////////////////////////////////////////// + + public: + static std::shared_ptr create(const std::shared_ptr& io_context + , std::uint8_t protocol_version + , std::uint16_t port + , const ServerServiceCallbackT& service_callback + , bool parallel_service_calls_enabled + , const ServerEventCallbackT& event_callback + , const LoggerT& logger = default_logger("Service Server")); + + protected: + ServerImpl(const std::shared_ptr& io_context + , const ServerServiceCallbackT& service_callback + , bool parallel_service_calls_enabled + , const ServerEventCallbackT& event_callback + , const LoggerT& logger); + + public: + ServerImpl(const ServerImpl&) = delete; // Copy construct + ServerImpl(ServerImpl&&) = delete; // Move construct + + ServerImpl& operator=(const ServerImpl&) = delete; // Copy assign + ServerImpl& operator=(ServerImpl&&) = delete; // Move assign + + ~ServerImpl(); + + /////////////////////////////////////////// + // API + /////////////////////////////////////////// + + public: + bool is_connected() const; + int get_connection_count() const; + std::uint16_t get_port() const; + + void stop(); + + private: + void start_accept(std::uint8_t protocol_version, std::uint16_t port); + void wait_for_next_client(std::uint8_t protocol_version); + + /////////////////////////////////////////// + // Member Variables + /////////////////////////////////////////// + + private: + const std::shared_ptr io_context_; + asio::ip::tcp::acceptor acceptor_; + mutable std::mutex acceptor_mutex_; //!< Mutex for stopping the server. The stop() function is both used externally (via API) and from within the server itself. Closing the acceptor is not thread-safe, so we need to protect it. + + const bool parallel_service_calls_enabled_; + const std::shared_ptr service_callback_common_strand_; + const ServerServiceCallbackT service_callback_; + const ServerEventCallbackT event_callback_; + + mutable std::mutex session_list_mutex_; + std::vector> session_list_; + + const LoggerT logger_; + + }; +} // namespace ecal_service diff --git a/ecal/service/ecal_service/src/server_manager.cpp b/ecal/service/ecal_service/src/server_manager.cpp index 2fad646d96..213d5480fe 100644 --- a/ecal/service/ecal_service/src/server_manager.cpp +++ b/ecal/service/ecal_service/src/server_manager.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ * ========================= eCAL LICENSE ================================= */ -#include +#include #include #include @@ -27,94 +27,91 @@ #include -#include -#include +#include +#include -namespace eCAL +namespace ecal_service { - namespace service + /////////////////////////////////////////////////////// + // Constructor, Destructor, Create + /////////////////////////////////////////////////////// + std::shared_ptr ServerManager::create(const std::shared_ptr& io_context, const LoggerT& logger) { - /////////////////////////////////////////////////////// - // Constructor, Destructor, Create - /////////////////////////////////////////////////////// - std::shared_ptr ServerManager::create(const std::shared_ptr& io_context, const LoggerT& logger) - { - return std::shared_ptr(new ServerManager(io_context, logger)); - } + return std::shared_ptr(new ServerManager(io_context, logger)); + } - ServerManager::ServerManager(const std::shared_ptr& io_context, const LoggerT& logger) - : io_context_(io_context) - , logger_(logger) - , stopped_(false) - , work_(std::make_unique(*io_context)) - {} + ServerManager::ServerManager(const std::shared_ptr& io_context, const LoggerT& logger) + : io_context_(io_context) + , logger_(logger) + , stopped_(false) + , work_(std::make_unique(*io_context)) + {} - ServerManager::~ServerManager() - { - stop(); - } + ServerManager::~ServerManager() + { + stop(); + } - /////////////////////////////////////////////////////// - // Public API - /////////////////////////////////////////////////////// - std::shared_ptr ServerManager::create_server(std::uint8_t protocol_version - , std::uint16_t port - , const Server::ServiceCallbackT& service_callback - , bool parallel_service_calls_enabled - , const Server::EventCallbackT& event_callback) + /////////////////////////////////////////////////////// + // Public API + /////////////////////////////////////////////////////// + std::shared_ptr ServerManager::create_server(std::uint8_t protocol_version + , std::uint16_t port + , const Server::ServiceCallbackT& service_callback + , bool parallel_service_calls_enabled + , const Server::EventCallbackT& event_callback) + { + const std::lock_guard lock(server_manager_mutex_); + if (stopped_) { - const std::lock_guard lock(server_manager_mutex_); - if (stopped_) - { - return nullptr; - } + return nullptr; + } - auto delete_callback = [weak_me = std::weak_ptr(shared_from_this())](Server* server) + auto delete_callback = [weak_me = std::weak_ptr(shared_from_this())](Server* server) + { + auto me = weak_me.lock(); + if (me) { - auto me = weak_me.lock(); - if (me) - { - // Remove the session from the sessions_ map - const std::lock_guard lock(me->server_manager_mutex_); - me->sessions_.erase(server); - } - }; - auto server = Server::create(io_context_, protocol_version, port, service_callback, parallel_service_calls_enabled, event_callback, logger_, delete_callback); - sessions_.emplace(server.get(), server); - return server; - } + // Remove the session from the sessions_ map + const std::lock_guard lock(me->server_manager_mutex_); + me->sessions_.erase(server); + } + }; + auto server = Server::create(io_context_, protocol_version, port, service_callback, parallel_service_calls_enabled, event_callback, logger_, delete_callback); + sessions_.emplace(server.get(), server); + return server; + } - size_t ServerManager::server_count() const + size_t ServerManager::server_count() const + { + const std::lock_guard lock(server_manager_mutex_); + return sessions_.size(); + } + + void ServerManager::stop() + { + std::map> sessions_copy; { const std::lock_guard lock(server_manager_mutex_); - return sessions_.size(); + stopped_ = true; + sessions_copy = sessions_; } - void ServerManager::stop() + // stop all dservers without having the mutex locked, so we don't crash, when this thread directly calls the delete callback, that itself needs to have the mutex locked. + for (auto& server_weak : sessions_copy) { - std::map> sessions_copy; - { - const std::lock_guard lock(server_manager_mutex_); - stopped_ = true; - sessions_copy = sessions_; - } - - // stop all dservers without having the mutex locked, so we don't crash, when this thread directly calls the delete callback, that itself needs to have the mutex locked. - for (auto& server_weak : sessions_copy) - { - auto server = server_weak.second.lock(); - if (server) - server->stop(); - } - - work_.reset(); + auto server = server_weak.second.lock(); + if (server) + server->stop(); } - bool ServerManager::is_stopped() const - { - const std::lock_guard lock(server_manager_mutex_); - return stopped_; - } + work_.reset(); + } + bool ServerManager::is_stopped() const + { + const std::lock_guard lock(server_manager_mutex_); + return stopped_; } + } diff --git a/ecal/service/ecal_service/src/server_session_impl_base.h b/ecal/service/ecal_service/src/server_session_impl_base.h index ff663e28cf..41ac5b5d31 100644 --- a/ecal/service/ecal_service/src/server_session_impl_base.h +++ b/ecal/service/ecal_service/src/server_session_impl_base.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,71 +35,68 @@ #pragma warning(pop) #endif -#include -#include +#include +#include -namespace eCAL +namespace ecal_service { - namespace service + class ServerSessionBase { - class ServerSessionBase - { - ///////////////////////////////////// - // Custom types for API - ///////////////////////////////////// - public: - using ShutdownCallbackT = std::function&)>; - - ///////////////////////////////////// - // Constructor, Destructor, Create - ///////////////////////////////////// - public: - // Delete copy / move constructor and assignment operator - ServerSessionBase(const ServerSessionBase&) = delete; // Copy construct - ServerSessionBase(ServerSessionBase&&) = delete; // Move construct - - ServerSessionBase& operator=(const ServerSessionBase&) = delete; // Copy assign - ServerSessionBase& operator=(ServerSessionBase&&) = delete; // Move assign - - virtual ~ServerSessionBase() = default; - - protected: - ServerSessionBase(const std::shared_ptr& io_context - , const ServerServiceCallbackT& service_callback - , const std::shared_ptr& service_callback_strand - , const ServerEventCallbackT& event_callback - , const ShutdownCallbackT& shutdown_callback) - : io_context_ (io_context) - , socket_ (*io_context) - , service_callback_ (service_callback) - , service_callback_strand_(service_callback_strand) - , event_callback_ (event_callback) - , shutdown_callback_ (shutdown_callback) - {} - - ///////////////////////////////////// - // Public API - ///////////////////////////////////// - public: - asio::ip::tcp::socket& socket() { return socket_; } - virtual void start() = 0; - virtual void stop() = 0; - - virtual eCAL::service::State get_state() const = 0; - - ///////////////////////////////////// - // Member variables - ///////////////////////////////////// - protected: - const std::shared_ptr io_context_; - asio::ip::tcp::socket socket_; - mutable std::mutex socket_mutex_; - - const ServerServiceCallbackT service_callback_; - const std::shared_ptr service_callback_strand_; - const ServerEventCallbackT event_callback_; - const ShutdownCallbackT shutdown_callback_; - }; - - } // namespace service -} // namespace eCAL + ///////////////////////////////////// + // Custom types for API + ///////////////////////////////////// + public: + using ShutdownCallbackT = std::function&)>; + + ///////////////////////////////////// + // Constructor, Destructor, Create + ///////////////////////////////////// + public: + // Delete copy / move constructor and assignment operator + ServerSessionBase(const ServerSessionBase&) = delete; // Copy construct + ServerSessionBase(ServerSessionBase&&) = delete; // Move construct + + ServerSessionBase& operator=(const ServerSessionBase&) = delete; // Copy assign + ServerSessionBase& operator=(ServerSessionBase&&) = delete; // Move assign + + virtual ~ServerSessionBase() = default; + + protected: + ServerSessionBase(const std::shared_ptr& io_context + , const ServerServiceCallbackT& service_callback + , const std::shared_ptr& service_callback_strand + , const ServerEventCallbackT& event_callback + , const ShutdownCallbackT& shutdown_callback) + : io_context_ (io_context) + , socket_ (*io_context) + , service_callback_ (service_callback) + , service_callback_strand_(service_callback_strand) + , event_callback_ (event_callback) + , shutdown_callback_ (shutdown_callback) + {} + + ///////////////////////////////////// + // Public API + ///////////////////////////////////// + public: + asio::ip::tcp::socket& socket() { return socket_; } + virtual void start() = 0; + virtual void stop() = 0; + + virtual ecal_service::State get_state() const = 0; + + ///////////////////////////////////// + // Member variables + ///////////////////////////////////// + protected: + const std::shared_ptr io_context_; + asio::ip::tcp::socket socket_; + mutable std::mutex socket_mutex_; + + const ServerServiceCallbackT service_callback_; + const std::shared_ptr service_callback_strand_; + const ServerEventCallbackT event_callback_; + const ShutdownCallbackT shutdown_callback_; + }; + +} // namespace ecal_service diff --git a/ecal/service/ecal_service/src/server_session_impl_v1.cpp b/ecal/service/ecal_service/src/server_session_impl_v1.cpp index 568e524aef..e57728bc18 100644 --- a/ecal/service/ecal_service/src/server_session_impl_v1.cpp +++ b/ecal/service/ecal_service/src/server_session_impl_v1.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,9 +34,9 @@ #include -#include -#include -#include +#include +#include +#include #ifdef WIN32 #include @@ -48,297 +48,294 @@ // Create, Constructor, Destructor /////////////////////////////////////////////// -namespace eCAL +namespace ecal_service { - namespace service + constexpr std::uint8_t ServerSessionV1::MIN_SUPPORTED_PROTOCOL_VERSION; + constexpr std::uint8_t ServerSessionV1::MAX_SUPPORTED_PROTOCOL_VERSION; + + std::shared_ptr ServerSessionV1::create(const std::shared_ptr& io_context + , const ServerServiceCallbackT& service_callback + , const std::shared_ptr& service_callback_strand + , const ServerEventCallbackT& event_callback + , const ShutdownCallbackT& shutdown_callback + , const LoggerT& logger) { - constexpr std::uint8_t ServerSessionV1::MIN_SUPPORTED_PROTOCOL_VERSION; - constexpr std::uint8_t ServerSessionV1::MAX_SUPPORTED_PROTOCOL_VERSION; - - std::shared_ptr ServerSessionV1::create(const std::shared_ptr& io_context - , const ServerServiceCallbackT& service_callback - , const std::shared_ptr& service_callback_strand - , const ServerEventCallbackT& event_callback - , const ShutdownCallbackT& shutdown_callback - , const LoggerT& logger) - { - std::shared_ptr instance = std::shared_ptr(new ServerSessionV1(io_context, service_callback, service_callback_strand, event_callback, shutdown_callback, logger)); - return instance; - } - - ServerSessionV1::ServerSessionV1(const std::shared_ptr& io_context - , const ServerServiceCallbackT& service_callback - , const std::shared_ptr& service_callback_strand - , const ServerEventCallbackT& event_callback - , const ShutdownCallbackT& shutdown_callback - , const LoggerT& logger) - : ServerSessionBase(io_context, service_callback, service_callback_strand, event_callback, shutdown_callback) - , state_ (State::NOT_CONNECTED) - , accepted_protocol_version_(0) - , logger_ (logger) - { - ECAL_SERVICE_LOG_DEBUG_VERBOSE(logger_, "Server Session Created"); - } + std::shared_ptr instance = std::shared_ptr(new ServerSessionV1(io_context, service_callback, service_callback_strand, event_callback, shutdown_callback, logger)); + return instance; + } + + ServerSessionV1::ServerSessionV1(const std::shared_ptr& io_context + , const ServerServiceCallbackT& service_callback + , const std::shared_ptr& service_callback_strand + , const ServerEventCallbackT& event_callback + , const ShutdownCallbackT& shutdown_callback + , const LoggerT& logger) + : ServerSessionBase(io_context, service_callback, service_callback_strand, event_callback, shutdown_callback) + , state_ (State::NOT_CONNECTED) + , accepted_protocol_version_(0) + , logger_ (logger) + { + ECAL_SERVICE_LOG_DEBUG_VERBOSE(logger_, "Server Session Created"); + } - // Destructor - ServerSessionV1::~ServerSessionV1() - { - ServerSessionV1::stop(); - ECAL_SERVICE_LOG_DEBUG_VERBOSE(logger_, "Server Session Deleted"); - } + // Destructor + ServerSessionV1::~ServerSessionV1() + { + ServerSessionV1::stop(); + ECAL_SERVICE_LOG_DEBUG_VERBOSE(logger_, "Server Session Deleted"); + } + + /////////////////////////////////////////////// + // Data receiving and sending + /////////////////////////////////////////////// + void ServerSessionV1::start() + { + ECAL_SERVICE_LOG_DEBUG(logger_, "[" + get_connection_info_string(socket_) + "] " + "Starting..."); - /////////////////////////////////////////////// - // Data receiving and sending - /////////////////////////////////////////////// - void ServerSessionV1::start() + // Disable Nagle's algorithm. Nagles Algorithm will otherwise cause the + // Socket to wait for more data, if it encounters a frame that can still + // fit more data. Obviously, this is an awfull default behaviour, if we + // want to transmit our data in a timely fashion. { - ECAL_SERVICE_LOG_DEBUG(logger_, "[" + get_connection_info_string(socket_) + "] " + "Starting..."); - - // Disable Nagle's algorithm. Nagles Algorithm will otherwise cause the - // Socket to wait for more data, if it encounters a frame that can still - // fit more data. Obviously, this is an awfull default behaviour, if we - // want to transmit our data in a timely fashion. + asio::error_code socket_option_ec; { - asio::error_code socket_option_ec; - { - const std::lock_guard socket_lock(socket_mutex_); - socket_.set_option(asio::ip::tcp::no_delay(true), socket_option_ec); // NOLINT(bugprone-unused-return-value) -> We already get the value from the ec parameter - } - if (socket_option_ec) - { - logger_(LogLevel::Warning, "[" + get_connection_info_string(socket_) + "] " + "Failed setting tcp::no_delay option: " + socket_option_ec.message()); - } + const std::lock_guard socket_lock(socket_mutex_); + socket_.set_option(asio::ip::tcp::no_delay(true), socket_option_ec); // NOLINT(bugprone-unused-return-value) -> We already get the value from the ec parameter } - - receive_handshake_request(); + if (socket_option_ec) + { + logger_(LogLevel::Warning, "[" + get_connection_info_string(socket_) + "] " + "Failed setting tcp::no_delay option: " + socket_option_ec.message()); + } } - void ServerSessionV1::stop() + receive_handshake_request(); + } + + void ServerSessionV1::stop() + { + const std::lock_guard socket_lock(socket_mutex_); + if (socket_.is_open()) { - const std::lock_guard socket_lock(socket_mutex_); - if (socket_.is_open()) + ECAL_SERVICE_LOG_DEBUG(logger_, "[" + get_connection_info_string(socket_) + "] " + "Stopping..."); + { + // Shutdown the socket + asio::error_code ec; + socket_.shutdown(asio::ip::tcp::socket::shutdown_both, ec); // NOLINT(bugprone-unused-return-value) -> We already get the value from the ec parameter + } { - ECAL_SERVICE_LOG_DEBUG(logger_, "[" + get_connection_info_string(socket_) + "] " + "Stopping..."); - { - // Shutdown the socket - asio::error_code ec; - socket_.shutdown(asio::ip::tcp::socket::shutdown_both, ec); // NOLINT(bugprone-unused-return-value) -> We already get the value from the ec parameter - } - { - // Close the socket - asio::error_code ec; - socket_.close(ec); // NOLINT(bugprone-unused-return-value) -> We already get the value from the ec parameter - } + // Close the socket + asio::error_code ec; + socket_.close(ec); // NOLINT(bugprone-unused-return-value) -> We already get the value from the ec parameter } } + } - eCAL::service::State ServerSessionV1::get_state() const - { - return state_; - } + ecal_service::State ServerSessionV1::get_state() const + { + return state_; + } - void ServerSessionV1::receive_handshake_request() - { - ECAL_SERVICE_LOG_DEBUG(logger_, "[" + get_connection_info_string(socket_) + "] " + "Waiting for protocol handshake request..."); + void ServerSessionV1::receive_handshake_request() + { + ECAL_SERVICE_LOG_DEBUG(logger_, "[" + get_connection_info_string(socket_) + "] " + "Waiting for protocol handshake request..."); - // Go to handshake state - state_ = State::HANDSHAKE; + // Go to handshake state + state_ = State::HANDSHAKE; - eCAL::service::ProtocolV1::async_receive_payload(socket_, socket_mutex_ - , [me = shared_from_this()](asio::error_code ec) + ecal_service::ProtocolV1::async_receive_payload(socket_, socket_mutex_ + , [me = shared_from_this()](asio::error_code ec) + { + me->state_ = State::FAILED; + me->logger_(LogLevel::Error, "[" + get_connection_info_string(me->socket_) + "] " + "Failed receiving protocol handshake request: " + ec.message()); + me->shutdown_callback_(me); + } + , [me = shared_from_this()](const std::shared_ptr>& header_buffer, const std::shared_ptr& payload_buffer) + { + TcpHeaderV1* header = reinterpret_cast(header_buffer->data()); + if (header->message_type != ecal_service::MessageType::ProtocolHandshakeRequest) { + // The request is not a Handshake request. + const std::string message = "Received invalid handshake request from client. Expected message type " + + std::to_string(static_cast(ecal_service::MessageType::ProtocolHandshakeRequest)) + + ", but received " + std::to_string(static_cast(header->message_type)); + me->logger_(LogLevel::Fatal, "[" + get_connection_info_string(me->socket_) + "] " + message); + me->state_ = State::FAILED; - me->logger_(LogLevel::Error, "[" + get_connection_info_string(me->socket_) + "] " + "Failed receiving protocol handshake request: " + ec.message()); me->shutdown_callback_(me); + return; } - , [me = shared_from_this()](const std::shared_ptr>& header_buffer, const std::shared_ptr& payload_buffer) + else { - TcpHeaderV1* header = reinterpret_cast(header_buffer->data()); - if (header->message_type != eCAL::service::MessageType::ProtocolHandshakeRequest) + // The request is a Handshake request + ECAL_SERVICE_LOG_DEBUG_VERBOSE(me->logger_, "[" + get_connection_info_string(me->socket_) + "] " + "Received a handshake request of " + std::to_string(payload_buffer->size()) + " bytes."); + + // Resize payload if necessary. Will probably never be necessary + if (payload_buffer->size() < sizeof(ProtocolHandshakeRequestMessage)) { - // The request is not a Handshake request. - const std::string message = "Received invalid handshake request from client. Expected message type " - + std::to_string(static_cast(eCAL::service::MessageType::ProtocolHandshakeRequest)) - + ", but received " + std::to_string(static_cast(header->message_type)); - me->logger_(LogLevel::Fatal, "[" + get_connection_info_string(me->socket_) + "] " + message); + payload_buffer->resize(sizeof(ProtocolHandshakeRequestMessage), '\0'); + } + const ProtocolHandshakeRequestMessage* handshake_request = reinterpret_cast(payload_buffer->data()); - me->state_ = State::FAILED; - me->shutdown_callback_(me); - return; + // Compute the maximum supported protocol version by this server and the remote client + const std::uint8_t both_supported_max_protocol_version = std::min(handshake_request->max_supported_protocol_version, MAX_SUPPORTED_PROTOCOL_VERSION); + const std::uint8_t both_supported_min_protocol_version = std::max(handshake_request->min_supported_protocol_version, MIN_SUPPORTED_PROTOCOL_VERSION); + + if (both_supported_max_protocol_version >= both_supported_min_protocol_version) + { + // We have a protocol version that is supported by both sides. We choose the maximum supported version + me->accepted_protocol_version_ = both_supported_max_protocol_version; + ECAL_SERVICE_LOG_DEBUG_VERBOSE(me->logger_, "[" + get_connection_info_string(me->socket_) + "] " + "Choosing protocol version " + std::to_string(me->accepted_protocol_version_)); + + // Send the handshake response to the client, telling him the protocol version we will use + me->send_handshake_response(); } else { - // The request is a Handshake request - ECAL_SERVICE_LOG_DEBUG_VERBOSE(me->logger_, "[" + get_connection_info_string(me->socket_) + "] " + "Received a handshake request of " + std::to_string(payload_buffer->size()) + " bytes."); - - // Resize payload if necessary. Will probably never be necessary - if (payload_buffer->size() < sizeof(ProtocolHandshakeRequestMessage)) - { - payload_buffer->resize(sizeof(ProtocolHandshakeRequestMessage), '\0'); - } - const ProtocolHandshakeRequestMessage* handshake_request = reinterpret_cast(payload_buffer->data()); - - // Compute the maximum supported protocol version by this server and the remote client - const std::uint8_t both_supported_max_protocol_version = std::min(handshake_request->max_supported_protocol_version, MAX_SUPPORTED_PROTOCOL_VERSION); - const std::uint8_t both_supported_min_protocol_version = std::max(handshake_request->min_supported_protocol_version, MIN_SUPPORTED_PROTOCOL_VERSION); - - if (both_supported_max_protocol_version >= both_supported_min_protocol_version) - { - // We have a protocol version that is supported by both sides. We choose the maximum supported version - me->accepted_protocol_version_ = both_supported_max_protocol_version; - ECAL_SERVICE_LOG_DEBUG_VERBOSE(me->logger_, "[" + get_connection_info_string(me->socket_) + "] " + "Choosing protocol version " + std::to_string(me->accepted_protocol_version_)); - - // Send the handshake response to the client, telling him the protocol version we will use - me->send_handshake_response(); - } - else - { - const std::string message = std::string("Error while accepting connection from client. No common protocol version is found. ") - + "Client supports [min: " + std::to_string(handshake_request->min_supported_protocol_version) + ", max: " + std::to_string(handshake_request->max_supported_protocol_version) + "]. " - + "Server supports [min: " + std::to_string(MIN_SUPPORTED_PROTOCOL_VERSION) + ", max: " + std::to_string(MAX_SUPPORTED_PROTOCOL_VERSION) + "]."; - me->logger_(LogLevel::Error, "[" + get_connection_info_string(me->socket_) + "] " + message); - - //const auto message = get_log_string("ERROR", "Error connecting to server. Server reported an un-supported protocol version: " + std::to_string(handshake_response->accepted_protocol_version)); - //std::cerr << message << std::endl; - me->state_ = State::FAILED; - me->shutdown_callback_(me); - return; - } + const std::string message = std::string("Error while accepting connection from client. No common protocol version is found. ") + + "Client supports [min: " + std::to_string(handshake_request->min_supported_protocol_version) + ", max: " + std::to_string(handshake_request->max_supported_protocol_version) + "]. " + + "Server supports [min: " + std::to_string(MIN_SUPPORTED_PROTOCOL_VERSION) + ", max: " + std::to_string(MAX_SUPPORTED_PROTOCOL_VERSION) + "]."; + me->logger_(LogLevel::Error, "[" + get_connection_info_string(me->socket_) + "] " + message); + //const auto message = get_log_string("ERROR", "Error connecting to server. Server reported an un-supported protocol version: " + std::to_string(handshake_response->accepted_protocol_version)); + //std::cerr << message << std::endl; + me->state_ = State::FAILED; + me->shutdown_callback_(me); + return; } - }); - - } - - void ServerSessionV1::send_handshake_response() - { - ECAL_SERVICE_LOG_DEBUG(logger_, "[" + get_connection_info_string(socket_) + "] " + "Sending protocol handshake response..."); - - // Go to handshake state - state_ = State::HANDSHAKE; - // Create buffers - const std::shared_ptr header_buffer = std::make_shared(); - const std::shared_ptr payload_buffer = std::make_shared(); + } + }); - // Fill Handshake Response Message - payload_buffer->resize(sizeof(ProtocolHandshakeResponseMessage), '\0'); - ProtocolHandshakeResponseMessage* handshake_response_message = reinterpret_cast(const_cast(payload_buffer->data())); - handshake_response_message->accepted_protocol_version = accepted_protocol_version_; + } - // Fill TCP Header - header_buffer->package_size_n = htonl(static_cast(payload_buffer->size())); - header_buffer->version = accepted_protocol_version_; - header_buffer->message_type = MessageType::ProtocolHandshakeResponse; - header_buffer->header_size_n = htons(sizeof(TcpHeaderV1)); + void ServerSessionV1::send_handshake_response() + { + ECAL_SERVICE_LOG_DEBUG(logger_, "[" + get_connection_info_string(socket_) + "] " + "Sending protocol handshake response..."); + + // Go to handshake state + state_ = State::HANDSHAKE; + + // Create buffers + const std::shared_ptr header_buffer = std::make_shared(); + const std::shared_ptr payload_buffer = std::make_shared(); + + // Fill Handshake Response Message + payload_buffer->resize(sizeof(ProtocolHandshakeResponseMessage), '\0'); + ProtocolHandshakeResponseMessage* handshake_response_message = reinterpret_cast(const_cast(payload_buffer->data())); + handshake_response_message->accepted_protocol_version = accepted_protocol_version_; + + // Fill TCP Header + header_buffer->package_size_n = htonl(static_cast(payload_buffer->size())); + header_buffer->version = accepted_protocol_version_; + header_buffer->message_type = MessageType::ProtocolHandshakeResponse; + header_buffer->header_size_n = htons(sizeof(TcpHeaderV1)); + + ecal_service::ProtocolV1::async_send_payload(socket_, socket_mutex_,header_buffer, payload_buffer + , [me = shared_from_this()](asio::error_code ec) + { + me->state_ = State::FAILED; + me->logger_(LogLevel::Error, "[" + get_connection_info_string(me->socket_) + "] " + "Failed sending protocol handshake response: " + ec.message()); + me->shutdown_callback_(me); + } + , [me = shared_from_this()]() + { + me->state_ = State::CONNECTED; + ECAL_SERVICE_LOG_DEBUG_VERBOSE(me->logger_, "[" + get_connection_info_string(me->socket_) + "] " + "Successfully sent protocol handshake response."); + + const std::string message = "Client has connected. Using protocol version " + std::to_string(me->accepted_protocol_version_) + "."; + me->logger_(LogLevel::Info, "[" + get_connection_info_string(me->socket_) + "] " + message); + + me->state_ = State::CONNECTED; + + // call event callback + me->event_callback_(ecal_service::ServerEventType::Connected, message); + + me->receive_service_request(); + }); + } + + void ServerSessionV1::receive_service_request() + { + ECAL_SERVICE_LOG_DEBUG(logger_, "[" + get_connection_info_string(socket_) + "] " + "Waiting for service request..."); - eCAL::service::ProtocolV1::async_send_payload(socket_, socket_mutex_,header_buffer, payload_buffer + ecal_service::ProtocolV1::async_receive_payload(socket_, socket_mutex_ , [me = shared_from_this()](asio::error_code ec) { + const std::string message = "Server session disconnected while waiting for request: " + ec.message(); + me->logger_(LogLevel::Info, "[" + get_connection_info_string(me->socket_) + "] " + message); + me->state_ = State::FAILED; - me->logger_(LogLevel::Error, "[" + get_connection_info_string(me->socket_) + "] " + "Failed sending protocol handshake response: " + ec.message()); + + // call event callback + me->event_callback_(ecal_service::ServerEventType::Disconnected, message); me->shutdown_callback_(me); } - , [me = shared_from_this()]() + , service_callback_strand_->wrap([me = shared_from_this()](const std::shared_ptr>& header_buffer, const std::shared_ptr& payload_buffer) { - me->state_ = State::CONNECTED; - ECAL_SERVICE_LOG_DEBUG_VERBOSE(me->logger_, "[" + get_connection_info_string(me->socket_) + "] " + "Successfully sent protocol handshake response."); - - const std::string message = "Client has connected. Using protocol version " + std::to_string(me->accepted_protocol_version_) + "."; - me->logger_(LogLevel::Info, "[" + get_connection_info_string(me->socket_) + "] " + message); - - me->state_ = State::CONNECTED; - - // call event callback - me->event_callback_(eCAL::service::ServerEventType::Connected, message); - - me->receive_service_request(); - }); - } - - void ServerSessionV1::receive_service_request() - { - ECAL_SERVICE_LOG_DEBUG(logger_, "[" + get_connection_info_string(socket_) + "] " + "Waiting for service request..."); - - eCAL::service::ProtocolV1::async_receive_payload(socket_, socket_mutex_ - , [me = shared_from_this()](asio::error_code ec) + TcpHeaderV1* header = reinterpret_cast(header_buffer->data()); + if (header->message_type != ecal_service::MessageType::ServiceRequest) { - const std::string message = "Server session disconnected while waiting for request: " + ec.message(); - me->logger_(LogLevel::Info, "[" + get_connection_info_string(me->socket_) + "] " + message); + const std::string message = "Received invalid service request from client. Expected message type " + + std::to_string(static_cast(ecal_service::MessageType::ServiceRequest)) + + ", but received " + std::to_string(static_cast(header->message_type)); + me->logger_(LogLevel::Fatal, "[" + get_connection_info_string(me->socket_) + "] " + message); + // The request is not a Service request. me->state_ = State::FAILED; - + // call event callback - me->event_callback_(eCAL::service::ServerEventType::Disconnected, message); + me->event_callback_(ecal_service::ServerEventType::Disconnected, message); + me->shutdown_callback_(me); + return; } - , service_callback_strand_->wrap([me = shared_from_this()](const std::shared_ptr>& header_buffer, const std::shared_ptr& payload_buffer) + else { - TcpHeaderV1* header = reinterpret_cast(header_buffer->data()); - if (header->message_type != eCAL::service::MessageType::ServiceRequest) - { - const std::string message = "Received invalid service request from client. Expected message type " - + std::to_string(static_cast(eCAL::service::MessageType::ServiceRequest)) - + ", but received " + std::to_string(static_cast(header->message_type)); - me->logger_(LogLevel::Fatal, "[" + get_connection_info_string(me->socket_) + "] " + message); - - // The request is not a Service request. - me->state_ = State::FAILED; - - // call event callback - me->event_callback_(eCAL::service::ServerEventType::Disconnected, message); - - me->shutdown_callback_(me); - return; - } - else - { - // The request is a Service request - - ECAL_SERVICE_LOG_DEBUG(me->logger_, "[" + get_connection_info_string(me->socket_) + "] " + "Received service request of " + std::to_string(payload_buffer->size()) + " bytes"); + // The request is a Service request + + ECAL_SERVICE_LOG_DEBUG(me->logger_, "[" + get_connection_info_string(me->socket_) + "] " + "Received service request of " + std::to_string(payload_buffer->size()) + " bytes"); - // Call the service callback - const std::shared_ptr response_buffer = std::make_shared(); - me->service_callback_(payload_buffer, response_buffer); + // Call the service callback + const std::shared_ptr response_buffer = std::make_shared(); + me->service_callback_(payload_buffer, response_buffer); - // Send the response to the client - me->send_service_response(response_buffer); - } - })); + // Send the response to the client + me->send_service_response(response_buffer); + } + })); - } + } - void ServerSessionV1::send_service_response(const std::shared_ptr& response_buffer) - { - // Create header_buffer - const std::shared_ptr header_buffer = std::make_shared(); - header_buffer->package_size_n = htonl(static_cast(response_buffer->size())); - header_buffer->version = accepted_protocol_version_; - header_buffer->message_type = MessageType::ServiceResponse; - header_buffer->header_size_n = htons(sizeof(TcpHeaderV1)); + void ServerSessionV1::send_service_response(const std::shared_ptr& response_buffer) + { + // Create header_buffer + const std::shared_ptr header_buffer = std::make_shared(); + header_buffer->package_size_n = htonl(static_cast(response_buffer->size())); + header_buffer->version = accepted_protocol_version_; + header_buffer->message_type = MessageType::ServiceResponse; + header_buffer->header_size_n = htons(sizeof(TcpHeaderV1)); - ECAL_SERVICE_LOG_DEBUG(logger_, "[" + get_connection_info_string(socket_) + "] " + "Sending service response..."); + ECAL_SERVICE_LOG_DEBUG(logger_, "[" + get_connection_info_string(socket_) + "] " + "Sending service response..."); - eCAL::service::ProtocolV1::async_send_payload(socket_, socket_mutex_, header_buffer, response_buffer - , [me = shared_from_this()](asio::error_code ec) - { - const std::string message = "Failed sending service response: " + ec.message(); - me->logger_(LogLevel::Error, "[" + get_connection_info_string(me->socket_) + "] " + message); + ecal_service::ProtocolV1::async_send_payload(socket_, socket_mutex_, header_buffer, response_buffer + , [me = shared_from_this()](asio::error_code ec) + { + const std::string message = "Failed sending service response: " + ec.message(); + me->logger_(LogLevel::Error, "[" + get_connection_info_string(me->socket_) + "] " + message); - me->state_ = State::FAILED; - - // call event callback - me->event_callback_(eCAL::service::ServerEventType::Disconnected, message); - me->shutdown_callback_(me); - } - , [me = shared_from_this()]() - { - ECAL_SERVICE_LOG_DEBUG_VERBOSE(me->logger_, "[" + get_connection_info_string(me->socket_) + "] " + "Successfully sent service response."); + me->state_ = State::FAILED; + + // call event callback + me->event_callback_(ecal_service::ServerEventType::Disconnected, message); + me->shutdown_callback_(me); + } + , [me = shared_from_this()]() + { + ECAL_SERVICE_LOG_DEBUG_VERBOSE(me->logger_, "[" + get_connection_info_string(me->socket_) + "] " + "Successfully sent service response."); - // Wait for next request - me->receive_service_request(); - }); - } + // Wait for next request + me->receive_service_request(); + }); + } - } // namespace service -} // namespace eCAL +} // namespace ecal_service diff --git a/ecal/service/ecal_service/src/server_session_impl_v1.h b/ecal/service/ecal_service/src/server_session_impl_v1.h index 4a233270bb..a0807b6bad 100644 --- a/ecal/service/ecal_service/src/server_session_impl_v1.h +++ b/ecal/service/ecal_service/src/server_session_impl_v1.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ===== ============================ * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,78 +28,75 @@ #include -#include -#include -#include +#include +#include +#include -namespace eCAL +namespace ecal_service { - namespace service + class ServerSessionV1 + : public ServerSessionBase + , public std::enable_shared_from_this { - class ServerSessionV1 - : public ServerSessionBase - , public std::enable_shared_from_this - { + + /////////////////////////////////////////////// + // Create, Constructor, Destructor + /////////////////////////////////////////////// + + public: + static std::shared_ptr create(const std::shared_ptr& io_context + , const ServerServiceCallbackT& service_callback + , const std::shared_ptr& service_callback_strand + , const ServerEventCallbackT& event_callback + , const ShutdownCallbackT& shutdown_callback + , const LoggerT& logger); + + protected: + ServerSessionV1(const std::shared_ptr& io_context + , const ServerServiceCallbackT& service_callback + , const std::shared_ptr& service_callback_strand + , const ServerEventCallbackT& event_callback + , const ShutdownCallbackT& shutdown_callback + , const LoggerT& logger); + + public: + // Copy + ServerSessionV1(const ServerSessionV1&) = delete; + ServerSessionV1& operator=(const ServerSessionV1&) = delete; + + // Move + ServerSessionV1(ServerSessionV1&&) noexcept = delete; + ServerSessionV1& operator=(ServerSessionV1&&) noexcept = delete; + + // Destructor + ~ServerSessionV1() override; /////////////////////////////////////////////// - // Create, Constructor, Destructor + // Data receiving and sending /////////////////////////////////////////////// + public: + void start() override; + void stop() override; + + ecal_service::State get_state() const override; + + private: + void receive_handshake_request(); + void send_handshake_response(); + + void receive_service_request(); + void send_service_response(const std::shared_ptr& response_buffer); + + ///////////////////////////////////// + // Member variables + ///////////////////////////////////// + private: + static constexpr std::uint8_t MIN_SUPPORTED_PROTOCOL_VERSION = 1; + static constexpr std::uint8_t MAX_SUPPORTED_PROTOCOL_VERSION = 1; + + std::atomic state_; + std::uint8_t accepted_protocol_version_; - public: - static std::shared_ptr create(const std::shared_ptr& io_context - , const ServerServiceCallbackT& service_callback - , const std::shared_ptr& service_callback_strand - , const ServerEventCallbackT& event_callback - , const ShutdownCallbackT& shutdown_callback - , const LoggerT& logger); - - protected: - ServerSessionV1(const std::shared_ptr& io_context - , const ServerServiceCallbackT& service_callback - , const std::shared_ptr& service_callback_strand - , const ServerEventCallbackT& event_callback - , const ShutdownCallbackT& shutdown_callback - , const LoggerT& logger); - - public: - // Copy - ServerSessionV1(const ServerSessionV1&) = delete; - ServerSessionV1& operator=(const ServerSessionV1&) = delete; - - // Move - ServerSessionV1(ServerSessionV1&&) noexcept = delete; - ServerSessionV1& operator=(ServerSessionV1&&) noexcept = delete; - - // Destructor - ~ServerSessionV1() override; - - /////////////////////////////////////////////// - // Data receiving and sending - /////////////////////////////////////////////// - public: - void start() override; - void stop() override; - - eCAL::service::State get_state() const override; - - private: - void receive_handshake_request(); - void send_handshake_response(); - - void receive_service_request(); - void send_service_response(const std::shared_ptr& response_buffer); - - ///////////////////////////////////// - // Member variables - ///////////////////////////////////// - private: - static constexpr std::uint8_t MIN_SUPPORTED_PROTOCOL_VERSION = 1; - static constexpr std::uint8_t MAX_SUPPORTED_PROTOCOL_VERSION = 1; - - std::atomic state_; - std::uint8_t accepted_protocol_version_; - - const LoggerT logger_; - }; - } + const LoggerT logger_; + }; } diff --git a/ecal/service/samples/sample_client/src/main.cpp b/ecal/service/samples/sample_client/src/main.cpp index 403f981104..fa664f4a59 100644 --- a/ecal/service/samples/sample_client/src/main.cpp +++ b/ecal/service/samples/sample_client/src/main.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2023 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,10 +31,10 @@ #include -#include -#include -#include -#include +#include +#include +#include +#include void print_usage(const std::string& arg0) { @@ -113,7 +113,7 @@ int main(int argc, char** argv) auto io_context = std::make_shared(); // Create a client manager - auto client_manager = eCAL::service::ClientManager::create(io_context, eCAL::service::default_logger("Client", eCAL::service::LogLevel::DebugVerbose)); + auto client_manager = ecal_service::ClientManager::create(io_context, ecal_service::default_logger("Client", ecal_service::LogLevel::DebugVerbose)); // Create and start an io_context thread. // The io_context will be stopped, when the server_manager and client_manager are stopped. @@ -123,7 +123,7 @@ int main(int argc, char** argv) // // This callback will be called, when the service call is finished. auto client_response_callback - = [](const eCAL::service::Error& error, const std::shared_ptr& response) -> void + = [](const ecal_service::Error& error, const std::shared_ptr& response) -> void { if (error) std::cerr << "Error calling service: " << error.ToString() << std::endl; @@ -132,7 +132,7 @@ int main(int argc, char** argv) }; // Event callbacks (empty) - auto client_event_callback = [](eCAL::service::ClientEventType /*event*/, const std::string& /*message*/) {}; + auto client_event_callback = [](ecal_service::ClientEventType /*event*/, const std::string& /*message*/) {}; // Create client // The client will connect to the server on the given port. diff --git a/ecal/service/samples/sample_server/src/main.cpp b/ecal/service/samples/sample_server/src/main.cpp index d1a7921d6b..d01a3ce825 100644 --- a/ecal/service/samples/sample_server/src/main.cpp +++ b/ecal/service/samples/sample_server/src/main.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2023 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,9 +26,9 @@ #include -#include -#include -#include +#include +#include +#include void print_usage(const std::string& arg0) { @@ -93,7 +93,7 @@ int main(int argc, char** argv) auto io_context = std::make_shared(); // Create a server manager - auto server_manager = eCAL::service::ServerManager::create(io_context, eCAL::service::default_logger("Server", eCAL::service::LogLevel::DebugVerbose)); + auto server_manager = ecal_service::ServerManager::create(io_context, ecal_service::default_logger("Server", ecal_service::LogLevel::DebugVerbose)); // Server Service callback // @@ -106,7 +106,7 @@ int main(int argc, char** argv) }; // Event callbacks (empty) - auto server_event_callback = [](eCAL::service::ServerEventType /*event*/, const std::string& /*message*/) {}; + auto server_event_callback = [](ecal_service::ServerEventType /*event*/, const std::string& /*message*/) {}; // Create server // If the port is 0, the server will choose a port automatically diff --git a/ecal/service/samples/sample_standalone/src/main.cpp b/ecal/service/samples/sample_standalone/src/main.cpp index 482aaf4bce..ca9b2478e9 100644 --- a/ecal/service/samples/sample_standalone/src/main.cpp +++ b/ecal/service/samples/sample_standalone/src/main.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2023 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,12 +17,12 @@ * ========================= eCAL LICENSE ================================= */ -#include -#include +#include +#include -#include -#include -#include +#include +#include +#include #include #include @@ -38,8 +38,8 @@ int main(int /*argc*/, char** /*argv*/) auto io_context = std::make_shared(); // Create a server and client manager - auto server_manager = eCAL::service::ServerManager::create(io_context); - auto client_manager = eCAL::service::ClientManager::create(io_context); + auto server_manager = ecal_service::ServerManager::create(io_context); + auto client_manager = ecal_service::ClientManager::create(io_context); // Create and start an io_context thread. // The io_context will be stopped, when the server_manager and client_manager are stopped. @@ -59,7 +59,7 @@ int main(int /*argc*/, char** /*argv*/) // // This callback will be called, when the service call is finished. auto client_response_callback - = [](const eCAL::service::Error& error, const std::shared_ptr& response) -> void + = [](const ecal_service::Error& error, const std::shared_ptr& response) -> void { if (error) std::cerr << "Error calling service: " << error.ToString() << std::endl; @@ -68,8 +68,8 @@ int main(int /*argc*/, char** /*argv*/) }; // Event callbacks (empty) - auto server_event_callback = [](eCAL::service::ServerEventType /*event*/, const std::string& /*message*/) {}; - auto client_event_callback = [](eCAL::service::ClientEventType /*event*/, const std::string& /*message*/) {}; + auto server_event_callback = [](ecal_service::ServerEventType /*event*/, const std::string& /*message*/) {}; + auto client_event_callback = [](ecal_service::ClientEventType /*event*/, const std::string& /*message*/) {}; // Create server // The server will choose a free port automatically. diff --git a/ecal/service/test/src/ecal_tcp_service_test.cpp b/ecal/service/test/src/ecal_tcp_service_test.cpp index a79bd15e65..6e3ca32507 100644 --- a/ecal/service/test/src/ecal_tcp_service_test.cpp +++ b/ecal/service/test/src/ecal_tcp_service_test.cpp @@ -28,27 +28,27 @@ #include #include -#include // Should not be needed, when I use the server manager / client manager -#include // Should not be needed, when I use the server manager / client manager +#include // Should not be needed, when I use the server manager / client manager +#include // Should not be needed, when I use the server manager / client manager -#include -#include +#include +#include #include "atomic_signalable.h" -eCAL::service::LoggerT critical_logger(const std::string& node_name) +ecal_service::LoggerT critical_logger(const std::string& node_name) { - return [node_name](const eCAL::service::LogLevel log_level, const std::string& message) + return [node_name](const ecal_service::LogLevel log_level, const std::string& message) { switch (log_level) { - case eCAL::service::LogLevel::Warning: + case ecal_service::LogLevel::Warning: std::cerr << "[" + node_name + "] [Warning] " + message + "\n"; break; - case eCAL::service::LogLevel::Error: + case ecal_service::LogLevel::Error: std::cerr << "[" + node_name + "] [Error] " + message + "\n"; break; - case eCAL::service::LogLevel::Fatal: + case ecal_service::LogLevel::Fatal: std::cerr << "[" + node_name + "] [Fatal] " + message + "\n"; break; default: @@ -68,7 +68,7 @@ TEST(ecal_service, RAII_TcpServiceServer) // NOLINT const auto io_context = std::make_shared(); const asio::io_context::work dummy_work(*io_context); - const eCAL::service::Server::ServiceCallbackT service_callback + const ecal_service::Server::ServiceCallbackT service_callback = [](const std::shared_ptr& request, const std::shared_ptr& response) -> void { std::cout << "Server got request: " << *request << std::endl; @@ -76,8 +76,8 @@ TEST(ecal_service, RAII_TcpServiceServer) // NOLINT }; - const eCAL::service::Server::EventCallbackT event_callback - = [](eCAL::service::ServerEventType event, const std::string& message) -> void + const ecal_service::Server::EventCallbackT event_callback + = [](ecal_service::ServerEventType event, const std::string& message) -> void { std::cout << "Event " << static_cast(event) << ": " << message << std::endl; }; @@ -87,10 +87,10 @@ TEST(ecal_service, RAII_TcpServiceServer) // NOLINT // Test auto-destruction when the shared_ptr goes out of scope { - std::weak_ptr tcp_server_weak; + std::weak_ptr tcp_server_weak; { - const std::shared_ptr tcp_server = eCAL::service::Server::create(io_context, protocol_version, 0, service_callback, true, event_callback); + const std::shared_ptr tcp_server = ecal_service::Server::create(io_context, protocol_version, 0, service_callback, true, event_callback); tcp_server_weak = tcp_server; EXPECT_NE(nullptr, tcp_server); @@ -119,9 +119,9 @@ TEST(ecal_service, RAII_TcpServiceClient) // NOLINT const auto io_context = std::make_shared(); const asio::io_context::work dummy_work(*io_context); - const eCAL::service::ClientSession::EventCallbackT client_event_callback + const ecal_service::ClientSession::EventCallbackT client_event_callback = [] - (eCAL::service::ClientEventType /*event*/, const std::string& /*message*/) -> void + (ecal_service::ClientEventType /*event*/, const std::string& /*message*/) -> void {}; @@ -134,7 +134,7 @@ TEST(ecal_service, RAII_TcpServiceClient) // NOLINT io_context->run(); }); - auto client_v1 = eCAL::service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", 12345 }}, client_event_callback); + auto client_v1 = ecal_service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", 12345 }}, client_event_callback); io_context->stop(); io_thread->join(); @@ -152,30 +152,30 @@ TEST(ecal_service, RAII_TcpServiceServerAndClient) // NOLINT std::atomic response_callback_called(false); - const eCAL::service::Server::ServiceCallbackT server_service_callback + const ecal_service::Server::ServiceCallbackT server_service_callback = [](const std::shared_ptr& request, const std::shared_ptr& response) -> void { std::cout << "Server got request: " << *request << std::endl; *response = "Response on \"" + *request + "\""; }; - const eCAL::service::Server::EventCallbackT server_event_callback - = [](eCAL::service::ServerEventType event, const std::string& message) -> void + const ecal_service::Server::EventCallbackT server_event_callback + = [](ecal_service::ServerEventType event, const std::string& message) -> void { std::cout << "Event " << static_cast(event) << ": " << message << std::endl; }; - const eCAL::service::ClientSession::ResponseCallbackT client_slow_response_callback - = [&response_callback_called](const eCAL::service::Error& /*error*/, const std::shared_ptr& /*response*/) -> void + const ecal_service::ClientSession::ResponseCallbackT client_slow_response_callback + = [&response_callback_called](const ecal_service::Error& /*error*/, const std::shared_ptr& /*response*/) -> void { // This callback just wastes some time std::this_thread::sleep_for(std::chrono::milliseconds(100)); response_callback_called = true; }; - const eCAL::service::ClientSession::EventCallbackT client_event_callback + const ecal_service::ClientSession::EventCallbackT client_event_callback = [] - (eCAL::service::ClientEventType /*event*/, const std::string& /*message*/) -> void + (ecal_service::ClientEventType /*event*/, const std::string& /*message*/) -> void {}; @@ -184,13 +184,13 @@ TEST(ecal_service, RAII_TcpServiceServerAndClient) // NOLINT // Test auto-destruction when the shared_ptr goes out of scope { - std::weak_ptr tcp_server_weak; - std::weak_ptr tcp_client_weak; + std::weak_ptr tcp_server_weak; + std::weak_ptr tcp_client_weak; std::chrono::steady_clock::time_point start_time; { - const std::shared_ptr tcp_server = eCAL::service::Server::create(io_context, protocol_version, 0, server_service_callback, true, server_event_callback); + const std::shared_ptr tcp_server = ecal_service::Server::create(io_context, protocol_version, 0, server_service_callback, true, server_event_callback); tcp_server_weak = tcp_server; io_thread = std::make_unique([&io_context]() @@ -200,7 +200,7 @@ TEST(ecal_service, RAII_TcpServiceServerAndClient) // NOLINT EXPECT_EQ(tcp_server->get_connection_count(), 0); - auto client_v1 = eCAL::service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", tcp_server->get_port() }}, client_event_callback); + auto client_v1 = ecal_service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", tcp_server->get_port() }}, client_event_callback); tcp_client_weak = client_v1; client_v1->async_call_service(std::make_shared("Hello World"), client_slow_response_callback); @@ -239,30 +239,30 @@ TEST(ecal_service, RAII_StopDuringServiceCall) // NOLINT std::atomic response_callback_called(false); - const eCAL::service::Server::ServiceCallbackT server_service_callback + const ecal_service::Server::ServiceCallbackT server_service_callback = [](const std::shared_ptr& request, const std::shared_ptr& response) -> void { std::cout << "Server got request: " << *request << std::endl; *response = "Response on \"" + *request + "\""; }; - const eCAL::service::Server::EventCallbackT server_event_callback - = [](eCAL::service::ServerEventType event, const std::string& message) -> void + const ecal_service::Server::EventCallbackT server_event_callback + = [](ecal_service::ServerEventType event, const std::string& message) -> void { std::cout << "Event " << static_cast(event) << ": " << message << std::endl; }; - const eCAL::service::ClientSession::ResponseCallbackT client_slow_response_callback - = [&response_callback_called](const eCAL::service::Error& /*error*/, const std::shared_ptr& /*response*/) -> void + const ecal_service::ClientSession::ResponseCallbackT client_slow_response_callback + = [&response_callback_called](const ecal_service::Error& /*error*/, const std::shared_ptr& /*response*/) -> void { // This callback just wastes some time std::this_thread::sleep_for(std::chrono::milliseconds(100)); response_callback_called = true; }; - const eCAL::service::ClientSession::EventCallbackT client_event_callback + const ecal_service::ClientSession::EventCallbackT client_event_callback = [] - (eCAL::service::ClientEventType /*event*/, const std::string& /*message*/) -> void + (ecal_service::ClientEventType /*event*/, const std::string& /*message*/) -> void {}; std::unique_ptr io_thread; @@ -270,11 +270,11 @@ TEST(ecal_service, RAII_StopDuringServiceCall) // NOLINT // Test auto-destruction when the shared_ptr goes out of scope { - std::weak_ptr tcp_server_weak; - std::weak_ptr tcp_client_weak; + std::weak_ptr tcp_server_weak; + std::weak_ptr tcp_client_weak; { - const std::shared_ptr tcp_server = eCAL::service::Server::create(io_context, protocol_version, 0, server_service_callback, true, server_event_callback); + const std::shared_ptr tcp_server = ecal_service::Server::create(io_context, protocol_version, 0, server_service_callback, true, server_event_callback); tcp_server_weak = tcp_server; io_thread = std::make_unique([&io_context]() @@ -282,7 +282,7 @@ TEST(ecal_service, RAII_StopDuringServiceCall) // NOLINT io_context->run(); }); - auto client_v1 = eCAL::service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", tcp_server->get_port() }}, client_event_callback); + auto client_v1 = ecal_service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", tcp_server->get_port() }}, client_event_callback); tcp_client_weak = client_v1; client_v1->async_call_service(std::make_shared("Hello World"), client_slow_response_callback); @@ -319,7 +319,7 @@ TEST(ecal_service, Communication_SlowCommunication) // NOLINT std::atomic num_server_service_callback_called (0); std::atomic num_client_response_callback_called (0); - const eCAL::service::Server::ServiceCallbackT server_service_callback + const ecal_service::Server::ServiceCallbackT server_service_callback = [&num_server_service_callback_called] (const std::shared_ptr& request, const std::shared_ptr& response) -> void { @@ -328,26 +328,26 @@ TEST(ecal_service, Communication_SlowCommunication) // NOLINT *response = "Response on \"" + *request + "\""; }; - const eCAL::service::Server::EventCallbackT server_event_callback + const ecal_service::Server::EventCallbackT server_event_callback = [] - (eCAL::service::ServerEventType /*event*/, const std::string& /*message*/) -> void + (ecal_service::ServerEventType /*event*/, const std::string& /*message*/) -> void {}; - const eCAL::service::ClientSession::ResponseCallbackT client_response_callback + const ecal_service::ClientSession::ResponseCallbackT client_response_callback = [&num_client_response_callback_called] - (const eCAL::service::Error& error, const std::shared_ptr& response) -> void + (const ecal_service::Error& error, const std::shared_ptr& response) -> void { EXPECT_FALSE(bool(error)); num_client_response_callback_called++; std::cout << "Client got Response: " << *response << std::endl; }; - const eCAL::service::ClientSession::EventCallbackT client_event_callback + const ecal_service::ClientSession::EventCallbackT client_event_callback = [] - (eCAL::service::ClientEventType /*event*/, const std::string& /*message*/) -> void + (ecal_service::ClientEventType /*event*/, const std::string& /*message*/) -> void {}; - auto server = eCAL::service::Server::create(io_context, protocol_version, 0, server_service_callback, true, server_event_callback); + auto server = ecal_service::Server::create(io_context, protocol_version, 0, server_service_callback, true, server_event_callback); EXPECT_NE(server->get_port(), 0); @@ -358,7 +358,7 @@ TEST(ecal_service, Communication_SlowCommunication) // NOLINT EXPECT_EQ(server->get_connection_count(), 0); } - auto client_v1 = eCAL::service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", server->get_port() }}, client_event_callback); + auto client_v1 = ecal_service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", server->get_port() }}, client_event_callback); std::thread io_thread([&io_context]() { @@ -373,7 +373,7 @@ TEST(ecal_service, Communication_SlowCommunication) // NOLINT EXPECT_EQ(num_client_response_callback_called , 0); EXPECT_EQ(server->get_connection_count(), 1); - EXPECT_EQ(client_v1->get_state(), eCAL::service::State::CONNECTED); + EXPECT_EQ(client_v1->get_state(), ecal_service::State::CONNECTED); EXPECT_EQ(client_v1->get_accepted_protocol_version(), protocol_version); EXPECT_EQ(client_v1->get_queue_size(), 0); } @@ -388,7 +388,7 @@ TEST(ecal_service, Communication_SlowCommunication) // NOLINT EXPECT_EQ(num_client_response_callback_called , 1); EXPECT_EQ(server->get_connection_count(), 1); - EXPECT_EQ(client_v1->get_state(), eCAL::service::State::CONNECTED); + EXPECT_EQ(client_v1->get_state(), ecal_service::State::CONNECTED); EXPECT_EQ(client_v1->get_accepted_protocol_version(), protocol_version); EXPECT_EQ(client_v1->get_queue_size(), 0); } @@ -402,7 +402,7 @@ TEST(ecal_service, Communication_SlowCommunication) // NOLINT EXPECT_EQ(num_client_response_callback_called , 2); EXPECT_EQ(server->get_connection_count(), 1); - EXPECT_EQ(client_v1->get_state(), eCAL::service::State::CONNECTED); + EXPECT_EQ(client_v1->get_state(), ecal_service::State::CONNECTED); EXPECT_EQ(client_v1->get_accepted_protocol_version(), protocol_version); EXPECT_EQ(client_v1->get_queue_size(), 0); } @@ -434,42 +434,42 @@ TEST(ecal_service, CallbacksConnectDisconnect_ClientDisconnectsFirst) // NOLINT std::atomic num_client_event_callback_called_connected (0); std::atomic num_client_event_callback_called_disconnected(0); - const eCAL::service::Server::ServiceCallbackT server_service_callback + const ecal_service::Server::ServiceCallbackT server_service_callback = [] (const std::shared_ptr& /*request*/, const std::shared_ptr& /*response*/) -> void {}; - const eCAL::service::Server::EventCallbackT server_event_callback + const ecal_service::Server::EventCallbackT server_event_callback = [&num_server_event_callback_called, &num_server_event_callback_called_connected, &num_server_event_callback_called_disconnected] - (eCAL::service::ServerEventType event, const std::string& /*message*/) -> void + (ecal_service::ServerEventType event, const std::string& /*message*/) -> void { - if (event == eCAL::service::ServerEventType::Connected) + if (event == ecal_service::ServerEventType::Connected) num_server_event_callback_called_connected++; - else if (event == eCAL::service::ServerEventType::Disconnected) + else if (event == ecal_service::ServerEventType::Disconnected) num_server_event_callback_called_disconnected++; num_server_event_callback_called++; }; - const eCAL::service::ClientSession::ResponseCallbackT client_response_callback + const ecal_service::ClientSession::ResponseCallbackT client_response_callback = [] - (const eCAL::service::Error& /*error*/, const std::shared_ptr& /*response*/) -> void + (const ecal_service::Error& /*error*/, const std::shared_ptr& /*response*/) -> void {}; - const eCAL::service::ClientSession::EventCallbackT client_event_callback + const ecal_service::ClientSession::EventCallbackT client_event_callback = [&num_client_event_callback_called, &num_client_event_callback_called_connected, &num_client_event_callback_called_disconnected] - (eCAL::service::ClientEventType event, const std::string& /*message*/) -> void + (ecal_service::ClientEventType event, const std::string& /*message*/) -> void { - if (event == eCAL::service::ClientEventType::Connected) + if (event == ecal_service::ClientEventType::Connected) num_client_event_callback_called_connected++; - else if (event == eCAL::service::ClientEventType::Disconnected) + else if (event == ecal_service::ClientEventType::Disconnected) num_client_event_callback_called_disconnected++; num_client_event_callback_called++; }; - auto server = eCAL::service::Server::create(io_context, protocol_version, 0, server_service_callback, true, server_event_callback); - auto client = eCAL::service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", server->get_port() }}, client_event_callback); + auto server = ecal_service::Server::create(io_context, protocol_version, 0, server_service_callback, true, server_event_callback); + auto client = ecal_service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", server->get_port() }}, client_event_callback); std::thread io_thread([&io_context]() { @@ -543,7 +543,7 @@ TEST(ecal_service, CommunicationAndCallbacks_ClientsDisconnectFirst) // NOLINT std::atomic num_client_event_callback_called_connected (0); std::atomic num_client_event_callback_called_disconnected(0); - const eCAL::service::Server::ServiceCallbackT server_service_callback + const ecal_service::Server::ServiceCallbackT server_service_callback = [&num_server_service_callback_called] (const std::shared_ptr& request, const std::shared_ptr& response) -> void { @@ -552,40 +552,40 @@ TEST(ecal_service, CommunicationAndCallbacks_ClientsDisconnectFirst) // NOLINT num_server_service_callback_called++; }; - const eCAL::service::Server::EventCallbackT server_event_callback + const ecal_service::Server::EventCallbackT server_event_callback = [&num_server_event_callback_called, &num_server_event_callback_called_connected, &num_server_event_callback_called_disconnected] - (eCAL::service::ServerEventType event, const std::string& /*message*/) -> void + (ecal_service::ServerEventType event, const std::string& /*message*/) -> void { - if (event == eCAL::service::ServerEventType::Connected) + if (event == ecal_service::ServerEventType::Connected) num_server_event_callback_called_connected++; - else if (event == eCAL::service::ServerEventType::Disconnected) + else if (event == ecal_service::ServerEventType::Disconnected) num_server_event_callback_called_disconnected++; num_server_event_callback_called++; }; - const eCAL::service::ClientSession::ResponseCallbackT client_response_callback + const ecal_service::ClientSession::ResponseCallbackT client_response_callback = [&num_client_response_callback_called] - (const eCAL::service::Error& error, const std::shared_ptr& response) -> void + (const ecal_service::Error& error, const std::shared_ptr& response) -> void { EXPECT_FALSE(bool(error)); std::cout << "Client got Response: " << *response << std::endl; num_client_response_callback_called++; }; - const eCAL::service::ClientSession::EventCallbackT client_event_callback + const ecal_service::ClientSession::EventCallbackT client_event_callback = [&num_client_event_callback_called, &num_client_event_callback_called_connected, &num_client_event_callback_called_disconnected] - (eCAL::service::ClientEventType event, const std::string& /*message*/) -> void + (ecal_service::ClientEventType event, const std::string& /*message*/) -> void { - if (event == eCAL::service::ClientEventType::Connected) + if (event == ecal_service::ClientEventType::Connected) num_client_event_callback_called_connected++; - else if (event == eCAL::service::ClientEventType::Disconnected) + else if (event == ecal_service::ClientEventType::Disconnected) num_client_event_callback_called_disconnected++; num_client_event_callback_called++; }; - auto server = eCAL::service::Server::create(io_context, protocol_version, 0, server_service_callback, true, server_event_callback); + auto server = ecal_service::Server::create(io_context, protocol_version, 0, server_service_callback, true, server_event_callback); EXPECT_NE(server->get_port(), 0); @@ -603,7 +603,7 @@ TEST(ecal_service, CommunicationAndCallbacks_ClientsDisconnectFirst) // NOLINT EXPECT_EQ(server->get_connection_count(), 0); } - auto client_v1 = eCAL::service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", server->get_port() }}, client_event_callback); + auto client_v1 = ecal_service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", server->get_port() }}, client_event_callback); std::thread io_thread([&io_context]() { @@ -626,7 +626,7 @@ TEST(ecal_service, CommunicationAndCallbacks_ClientsDisconnectFirst) // NOLINT EXPECT_EQ(num_client_event_callback_called_disconnected, 0); EXPECT_EQ(server->get_connection_count(), 1); - EXPECT_EQ(client_v1->get_state(), eCAL::service::State::CONNECTED); + EXPECT_EQ(client_v1->get_state(), ecal_service::State::CONNECTED); EXPECT_EQ(client_v1->get_accepted_protocol_version(), protocol_version); EXPECT_EQ(client_v1->get_queue_size(), 0); } @@ -649,7 +649,7 @@ TEST(ecal_service, CommunicationAndCallbacks_ClientsDisconnectFirst) // NOLINT EXPECT_EQ(num_client_event_callback_called_disconnected, 0); EXPECT_EQ(server->get_connection_count(), 1); - EXPECT_EQ(client_v1->get_state(), eCAL::service::State::CONNECTED); + EXPECT_EQ(client_v1->get_state(), ecal_service::State::CONNECTED); EXPECT_EQ(client_v1->get_accepted_protocol_version(), protocol_version); EXPECT_EQ(client_v1->get_queue_size(), 0); } @@ -671,7 +671,7 @@ TEST(ecal_service, CommunicationAndCallbacks_ClientsDisconnectFirst) // NOLINT EXPECT_EQ(num_client_event_callback_called_disconnected, 0); EXPECT_EQ(server->get_connection_count(), 1); - EXPECT_EQ(client_v1->get_state(), eCAL::service::State::CONNECTED); + EXPECT_EQ(client_v1->get_state(), ecal_service::State::CONNECTED); EXPECT_EQ(client_v1->get_accepted_protocol_version(), protocol_version); EXPECT_EQ(client_v1->get_queue_size(), 0); } @@ -736,47 +736,47 @@ TEST(ecal_service, CommunicationAndCallbacks_ServerDisconnectsFirst) // NOLINT std::atomic num_client_event_callback_called_connected (0); std::atomic num_client_event_callback_called_disconnected(0); - const eCAL::service::Server::ServiceCallbackT server_service_callback + const ecal_service::Server::ServiceCallbackT server_service_callback = [&num_server_service_callback_called] (const std::shared_ptr& /*request*/, const std::shared_ptr& /*response*/) -> void { num_server_service_callback_called++; }; - const eCAL::service::Server::EventCallbackT server_event_callback + const ecal_service::Server::EventCallbackT server_event_callback = [&num_server_event_callback_called, &num_server_event_callback_called_connected, &num_server_event_callback_called_disconnected] - (eCAL::service::ServerEventType event, const std::string& /*message*/) -> void + (ecal_service::ServerEventType event, const std::string& /*message*/) -> void { - if (event == eCAL::service::ServerEventType::Connected) + if (event == ecal_service::ServerEventType::Connected) num_server_event_callback_called_connected++; - else if (event == eCAL::service::ServerEventType::Disconnected) + else if (event == ecal_service::ServerEventType::Disconnected) num_server_event_callback_called_disconnected++; num_server_event_callback_called++; }; - const eCAL::service::ClientSession::ResponseCallbackT client_response_callback + const ecal_service::ClientSession::ResponseCallbackT client_response_callback = [&num_client_response_callback_called] - (const eCAL::service::Error& error, const std::shared_ptr& /*response*/) -> void + (const ecal_service::Error& error, const std::shared_ptr& /*response*/) -> void { EXPECT_FALSE(bool(error)); num_client_response_callback_called++; }; - const eCAL::service::ClientSession::EventCallbackT client_event_callback + const ecal_service::ClientSession::EventCallbackT client_event_callback = [&num_client_event_callback_called, &num_client_event_callback_called_connected, &num_client_event_callback_called_disconnected] - (eCAL::service::ClientEventType event, const std::string& /*message*/) -> void + (ecal_service::ClientEventType event, const std::string& /*message*/) -> void { - if (event == eCAL::service::ClientEventType::Connected) + if (event == ecal_service::ClientEventType::Connected) num_client_event_callback_called_connected++; - else if (event == eCAL::service::ClientEventType::Disconnected) + else if (event == ecal_service::ClientEventType::Disconnected) num_client_event_callback_called_disconnected++; num_client_event_callback_called++; }; - auto server = eCAL::service::Server::create(io_context, protocol_version, 0, server_service_callback, true, server_event_callback); - auto client_v1 = eCAL::service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", server->get_port() }}, client_event_callback); + auto server = ecal_service::Server::create(io_context, protocol_version, 0, server_service_callback, true, server_event_callback); + auto client_v1 = ecal_service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", server->get_port() }}, client_event_callback); std::thread io_thread([&io_context]() { @@ -798,7 +798,7 @@ TEST(ecal_service, CommunicationAndCallbacks_ServerDisconnectsFirst) // NOLINT EXPECT_EQ(num_client_event_callback_called_disconnected, 0); EXPECT_EQ(server->get_connection_count(), 1); - EXPECT_EQ(client_v1->get_state(), eCAL::service::State::CONNECTED); + EXPECT_EQ(client_v1->get_state(), ecal_service::State::CONNECTED); EXPECT_EQ(client_v1->get_accepted_protocol_version(), protocol_version); EXPECT_EQ(client_v1->get_queue_size(), 0); } @@ -819,7 +819,7 @@ TEST(ecal_service, CommunicationAndCallbacks_ServerDisconnectsFirst) // NOLINT EXPECT_EQ(num_client_event_callback_called_connected , 1); EXPECT_EQ(num_client_event_callback_called_disconnected, 0); - EXPECT_EQ(client_v1->get_state(), eCAL::service::State::CONNECTED); + EXPECT_EQ(client_v1->get_state(), ecal_service::State::CONNECTED); EXPECT_EQ(client_v1->get_accepted_protocol_version(), protocol_version); EXPECT_EQ(client_v1->get_queue_size(), 0); } @@ -840,7 +840,7 @@ TEST(ecal_service, CommunicationAndCallbacks_ServerDisconnectsFirst) // NOLINT EXPECT_EQ(num_client_event_callback_called_connected , 1); EXPECT_EQ(num_client_event_callback_called_disconnected, 1); - EXPECT_EQ(client_v1->get_state(), eCAL::service::State::FAILED); + EXPECT_EQ(client_v1->get_state(), ecal_service::State::FAILED); EXPECT_EQ(client_v1->get_accepted_protocol_version(), protocol_version); EXPECT_EQ(client_v1->get_queue_size(), 0); } @@ -888,26 +888,26 @@ TEST(ecal_service, CommunicationAndCallbacks_StressfulCommunication) // NOLINT std::atomic num_client_event_callback_called_connected (0); std::atomic num_client_event_callback_called_disconnected(0); - const eCAL::service::Server::ServiceCallbackT service_callback + const ecal_service::Server::ServiceCallbackT service_callback = [&num_server_service_callback_called](const std::shared_ptr& request, const std::shared_ptr& response) -> void { num_server_service_callback_called++; *response = "Response on \"" + *request + "\""; }; - const eCAL::service::Server::EventCallbackT server_event_callback + const ecal_service::Server::EventCallbackT server_event_callback = [&num_server_event_callback_called, &num_server_event_callback_called_connected, &num_server_event_callback_called_disconnected] - (eCAL::service::ServerEventType event, const std::string& /*message*/) -> void + (ecal_service::ServerEventType event, const std::string& /*message*/) -> void { - if (event == eCAL::service::ServerEventType::Connected) + if (event == ecal_service::ServerEventType::Connected) num_server_event_callback_called_connected++; - else if (event == eCAL::service::ServerEventType::Disconnected) + else if (event == ecal_service::ServerEventType::Disconnected) num_server_event_callback_called_disconnected++; num_server_event_callback_called++; }; - auto server = eCAL::service::Server::create(io_context, protocol_version, 0, service_callback, true, server_event_callback, critical_logger("Server")); + auto server = ecal_service::Server::create(io_context, protocol_version, 0, service_callback, true, server_event_callback, critical_logger("Server")); { EXPECT_EQ(num_server_service_callback_called.get() , 0); @@ -930,22 +930,22 @@ TEST(ecal_service, CommunicationAndCallbacks_StressfulCommunication) // NOLINT } // Create all the clients - std::vector> client_list; + std::vector> client_list; client_list.reserve(num_clients); for (int c = 0; c < num_clients; c++) { - const eCAL::service::ClientSession::EventCallbackT client_event_callback + const ecal_service::ClientSession::EventCallbackT client_event_callback = [&num_client_event_callback_called, &num_client_event_callback_called_connected, &num_client_event_callback_called_disconnected] - (eCAL::service::ClientEventType event, const std::string& /*message*/) -> void + (ecal_service::ClientEventType event, const std::string& /*message*/) -> void { - if (event == eCAL::service::ClientEventType::Connected) + if (event == ecal_service::ClientEventType::Connected) num_client_event_callback_called_connected++; - else if (event == eCAL::service::ClientEventType::Disconnected) + else if (event == ecal_service::ClientEventType::Disconnected) num_client_event_callback_called_disconnected++; num_client_event_callback_called++; }; - client_list.push_back(eCAL::service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", server->get_port() }}, client_event_callback, critical_logger("Client " + std::to_string(c)))); + client_list.push_back(ecal_service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", server->get_port() }}, client_event_callback, critical_logger("Client " + std::to_string(c)))); } // Directly run a bunch of clients and call each client a bunch of times @@ -955,9 +955,9 @@ TEST(ecal_service, CommunicationAndCallbacks_StressfulCommunication) // NOLINT { const std::shared_ptr request_string = std::make_shared("Client " + std::to_string(c) + ", Call " + std::to_string(i)); - const eCAL::service::ClientSession::ResponseCallbackT response_callback + const ecal_service::ClientSession::ResponseCallbackT response_callback = [&num_client_response_callback_called, request_string] - (const eCAL::service::Error& error, const std::shared_ptr& response) -> void + (const ecal_service::Error& error, const std::shared_ptr& response) -> void { ASSERT_FALSE(error); num_client_response_callback_called++; @@ -1040,7 +1040,7 @@ TEST(ecal_service, CommunicationAndCallbacks_StressfulCommunicationNoParallelCal atomic_signalable num_client_response_callback_called (0); atomic_signalable num_clients_connected (0); - const eCAL::service::Server::ServiceCallbackT service_callback + const ecal_service::Server::ServiceCallbackT service_callback = [&num_server_service_callback_started, &num_server_service_callback_finished, server_time_to_waste] (const std::shared_ptr& request, const std::shared_ptr& response) -> void { @@ -1051,12 +1051,12 @@ TEST(ecal_service, CommunicationAndCallbacks_StressfulCommunicationNoParallelCal num_server_service_callback_finished++; }; - const eCAL::service::Server::EventCallbackT server_event_callback + const ecal_service::Server::EventCallbackT server_event_callback = [] - (eCAL::service::ServerEventType /*event*/, const std::string& /*message*/) -> void + (ecal_service::ServerEventType /*event*/, const std::string& /*message*/) -> void {}; - auto server = eCAL::service::Server::create(io_context, protocol_version, 0, service_callback, false, server_event_callback, critical_logger("Server")); + auto server = ecal_service::Server::create(io_context, protocol_version, 0, service_callback, false, server_event_callback, critical_logger("Server")); { EXPECT_EQ(num_server_service_callback_started , 0); @@ -1073,20 +1073,20 @@ TEST(ecal_service, CommunicationAndCallbacks_StressfulCommunicationNoParallelCal } // Create all the clients - std::vector> client_list; + std::vector> client_list; client_list.reserve(num_clients); for (int c = 0; c < num_clients; c++) { - const eCAL::service::ClientSession::EventCallbackT client_event_callback + const ecal_service::ClientSession::EventCallbackT client_event_callback = [&num_clients_connected] - (eCAL::service::ClientEventType event, const std::string& /*message*/) -> void + (ecal_service::ClientEventType event, const std::string& /*message*/) -> void { - if (event == eCAL::service::ClientEventType::Connected) + if (event == ecal_service::ClientEventType::Connected) { num_clients_connected++; } }; - client_list.push_back(eCAL::service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", server->get_port() }}, client_event_callback, critical_logger("Client " + std::to_string(c)))); + client_list.push_back(ecal_service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", server->get_port() }}, client_event_callback, critical_logger("Client " + std::to_string(c)))); } // wait for the clients to connect @@ -1104,9 +1104,9 @@ TEST(ecal_service, CommunicationAndCallbacks_StressfulCommunicationNoParallelCal { const std::shared_ptr request_string = std::make_shared("Client " + std::to_string(c) + ", Call " + std::to_string(i)); - const eCAL::service::ClientSession::ResponseCallbackT response_callback + const ecal_service::ClientSession::ResponseCallbackT response_callback = [&num_client_response_callback_called, request_string] - (const eCAL::service::Error& error, const std::shared_ptr& response) -> void + (const ecal_service::Error& error, const std::shared_ptr& response) -> void { ASSERT_FALSE(error); num_client_response_callback_called++; @@ -1175,7 +1175,7 @@ TEST(ecal_service, CommunicationAndCallbacks_StressfulCommunicationMassivePayloa std::atomic num_client_event_callback_called_connected (0); std::atomic num_client_event_callback_called_disconnected(0); - const eCAL::service::Server::ServiceCallbackT service_callback + const ecal_service::Server::ServiceCallbackT service_callback = [&num_server_service_callback_called, payload_size_bytes](const std::shared_ptr& request, const std::shared_ptr& response) -> void { EXPECT_EQ(request->size(), payload_size_bytes); @@ -1183,19 +1183,19 @@ TEST(ecal_service, CommunicationAndCallbacks_StressfulCommunicationMassivePayloa *response = *request; }; - const eCAL::service::Server::EventCallbackT server_event_callback + const ecal_service::Server::EventCallbackT server_event_callback = [&num_server_event_callback_called, &num_server_event_callback_called_connected, &num_server_event_callback_called_disconnected] - (eCAL::service::ServerEventType event, const std::string& /*message*/) -> void + (ecal_service::ServerEventType event, const std::string& /*message*/) -> void { num_server_event_callback_called++; - if (event == eCAL::service::ServerEventType::Connected) + if (event == ecal_service::ServerEventType::Connected) num_server_event_callback_called_connected++; - else if (event == eCAL::service::ServerEventType::Disconnected) + else if (event == ecal_service::ServerEventType::Disconnected) num_server_event_callback_called_disconnected++; }; - auto server = eCAL::service::Server::create(io_context, protocol_version, 0, service_callback, true, server_event_callback, critical_logger("Server")); + auto server = ecal_service::Server::create(io_context, protocol_version, 0, service_callback, true, server_event_callback, critical_logger("Server")); { EXPECT_EQ(num_server_service_callback_called.get() , 0); @@ -1218,22 +1218,22 @@ TEST(ecal_service, CommunicationAndCallbacks_StressfulCommunicationMassivePayloa } // Create all the clients - std::vector> client_list; + std::vector> client_list; client_list.reserve(num_clients); for (int c = 0; c < num_clients; c++) { - const eCAL::service::ClientSession::EventCallbackT client_event_callback + const ecal_service::ClientSession::EventCallbackT client_event_callback = [&num_client_event_callback_called, &num_client_event_callback_called_connected, &num_client_event_callback_called_disconnected] - (eCAL::service::ClientEventType event, const std::string& /*message*/) -> void + (ecal_service::ClientEventType event, const std::string& /*message*/) -> void { - if (event == eCAL::service::ClientEventType::Connected) + if (event == ecal_service::ClientEventType::Connected) num_client_event_callback_called_connected++; - else if (event == eCAL::service::ClientEventType::Disconnected) + else if (event == ecal_service::ClientEventType::Disconnected) num_client_event_callback_called_disconnected++; num_client_event_callback_called++; }; - client_list.push_back(eCAL::service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", server->get_port() }}, client_event_callback, critical_logger("Client " + std::to_string(c)))); + client_list.push_back(ecal_service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", server->get_port() }}, client_event_callback, critical_logger("Client " + std::to_string(c)))); } // Directly run a bunch of clients and call each client a bunch of times @@ -1241,9 +1241,9 @@ TEST(ecal_service, CommunicationAndCallbacks_StressfulCommunicationMassivePayloa { for (int i = 0; i < num_calls_per_client; i++) { - const eCAL::service::ClientSession::ResponseCallbackT response_callback + const ecal_service::ClientSession::ResponseCallbackT response_callback = [&num_client_response_callback_called, payload_size_bytes] - (const eCAL::service::Error& error, const std::shared_ptr& response) -> void + (const ecal_service::Error& error, const std::shared_ptr& response) -> void { ASSERT_FALSE(error); EXPECT_EQ(response->size(), payload_size_bytes); @@ -1315,8 +1315,8 @@ TEST(ecal_service, Callback_ServerAndClientManagers) // NOLINT io_threads.reserve(num_io_threads); const auto io_context = std::make_shared(); - auto client_manager = eCAL::service::ClientManager::create(io_context); - auto server_manager = eCAL::service::ServerManager::create(io_context); + auto client_manager = ecal_service::ClientManager::create(io_context); + auto server_manager = ecal_service::ServerManager::create(io_context); atomic_signalable server1_event_callback_called(0); atomic_signalable server2_event_callback_called(0); @@ -1334,8 +1334,8 @@ TEST(ecal_service, Callback_ServerAndClientManagers) // NOLINT })); } - const eCAL::service::Server::ServiceCallbackT server_service_callback = [](auto, auto) -> void {}; - const eCAL::service::ClientSession::ResponseCallbackT client_response_callback = [](auto, auto) -> void {}; + const ecal_service::Server::ServiceCallbackT server_service_callback = [](auto, auto) -> void {}; + const ecal_service::ClientSession::ResponseCallbackT client_response_callback = [](auto, auto) -> void {}; // Lambda function that on call returns another lambda function that will increment the given atomic_signalable auto increment_atomic_signalable = [](auto& atomic_signalable) -> auto @@ -1452,37 +1452,37 @@ TEST(ecal_service, Callback_ServiceCallFromCallback) // NOLINT std::atomic num_client_response_callback1_called(0); std::atomic num_client_response_callback2_called(0); - const eCAL::service::Server::ServiceCallbackT server_service_callback + const ecal_service::Server::ServiceCallbackT server_service_callback = [&num_server_service_callback_called](const std::shared_ptr& /*request*/, const std::shared_ptr& /*response*/) -> void { num_server_service_callback_called++; }; - const eCAL::service::Server::EventCallbackT server_event_callback - = [](eCAL::service::ServerEventType /*event*/, const std::string& /*message*/) -> void + const ecal_service::Server::EventCallbackT server_event_callback + = [](ecal_service::ServerEventType /*event*/, const std::string& /*message*/) -> void {}; - const eCAL::service::ClientSession::EventCallbackT client_event_callback + const ecal_service::ClientSession::EventCallbackT client_event_callback = [] - (eCAL::service::ClientEventType /*event*/, const std::string& /*message*/) -> void + (ecal_service::ClientEventType /*event*/, const std::string& /*message*/) -> void {}; - auto server = eCAL::service::Server::create(io_context, protocol_version, 0, server_service_callback, true, server_event_callback); + auto server = ecal_service::Server::create(io_context, protocol_version, 0, server_service_callback, true, server_event_callback); EXPECT_EQ(num_server_service_callback_called, 0); EXPECT_EQ(num_client_response_callback1_called, 0); EXPECT_EQ(num_client_response_callback2_called, 0); - auto client_v1 = eCAL::service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", server->get_port() }}, client_event_callback); + auto client_v1 = ecal_service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", server->get_port() }}, client_event_callback); - const eCAL::service::ClientSession::ResponseCallbackT response_callback + const ecal_service::ClientSession::ResponseCallbackT response_callback = [&num_client_response_callback1_called, &num_client_response_callback2_called, client_v1] - (const eCAL::service::Error& error, const std::shared_ptr& /*response*/) -> void + (const ecal_service::Error& error, const std::shared_ptr& /*response*/) -> void { EXPECT_FALSE(bool(error)); num_client_response_callback1_called++; client_v1->async_call_service(std::make_shared("2") - , [&num_client_response_callback2_called](const eCAL::service::Error& error, const auto& /*response*/) -> void + , [&num_client_response_callback2_called](const ecal_service::Error& error, const auto& /*response*/) -> void { EXPECT_FALSE(bool(error)); num_client_response_callback2_called++; @@ -1520,8 +1520,8 @@ TEST(ecal_service, Callback_SerializedServiceCallbacks) // NOLINT constexpr int num_threads = 5; const auto io_context = std::make_shared(); - auto server_manager = eCAL::service::ServerManager::create(io_context); - auto client_manager = eCAL::service::ClientManager::create(io_context); + auto server_manager = ecal_service::ServerManager::create(io_context); + auto client_manager = ecal_service::ClientManager::create(io_context); std::vector threads; threads.reserve(num_threads); @@ -1538,7 +1538,7 @@ TEST(ecal_service, Callback_SerializedServiceCallbacks) // NOLINT atomic_signalable num_client_response_callback_called (0); atomic_signalable num_client_event_callback_called (0); - const eCAL::service::Server::ServiceCallbackT server_service_callback + const ecal_service::Server::ServiceCallbackT server_service_callback = [&num_server_service_callback_called, server_callback_wait_time] (const std::shared_ptr& request, const std::shared_ptr& response) -> void { @@ -1547,20 +1547,20 @@ TEST(ecal_service, Callback_SerializedServiceCallbacks) // NOLINT num_server_service_callback_called++; }; - const eCAL::service::Server::EventCallbackT server_event_callback + const ecal_service::Server::EventCallbackT server_event_callback = [] - (eCAL::service::ServerEventType /*event*/, const std::string& /*message*/) -> void + (ecal_service::ServerEventType /*event*/, const std::string& /*message*/) -> void {}; - const eCAL::service::ClientSession::EventCallbackT client_event_callback + const ecal_service::ClientSession::EventCallbackT client_event_callback = [&num_client_event_callback_called] - (eCAL::service::ClientEventType /*event*/, const std::string& /*message*/) -> void + (ecal_service::ClientEventType /*event*/, const std::string& /*message*/) -> void { num_client_event_callback_called++; }; auto server = server_manager->create_server(protocol_version, 0, server_service_callback, false, server_event_callback); - std::vector> clients; + std::vector> clients; clients.reserve(num_clients); for (int i = 0; i < num_clients; i++) { @@ -1576,7 +1576,7 @@ TEST(ecal_service, Callback_SerializedServiceCallbacks) // NOLINT auto response = std::make_shared(); auto client_response_callback = [&num_client_response_callback_called, response] - (const eCAL::service::Error& error, const std::shared_ptr& /*response*/) -> void + (const ecal_service::Error& error, const std::shared_ptr& /*response*/) -> void { EXPECT_FALSE(bool(error)); num_client_response_callback_called++; @@ -1619,10 +1619,10 @@ TEST(ecal_service, Callback_ApiCallsFromCallbacks) // NOLINT atomic_signalable num_client_event_callback_called (0); // declare server and client shared_ptrs as we need those in the callbacks. - std::shared_ptr server; - std::shared_ptr client; + std::shared_ptr server; + std::shared_ptr client; - const eCAL::service::Server::ServiceCallbackT server_service_callback + const ecal_service::Server::ServiceCallbackT server_service_callback = [&num_server_service_callback_called, &server](const std::shared_ptr& /*request*/, const std::shared_ptr& /*response*/) -> void { if (server) @@ -1638,8 +1638,8 @@ TEST(ecal_service, Callback_ApiCallsFromCallbacks) // NOLINT num_server_service_callback_called++; }; - const eCAL::service::Server::EventCallbackT server_event_callback - = [&num_server_event_callback_called, &server](eCAL::service::ServerEventType event, const std::string& /*message*/) -> void + const ecal_service::Server::EventCallbackT server_event_callback + = [&num_server_event_callback_called, &server](ecal_service::ServerEventType event, const std::string& /*message*/) -> void { if (server) { @@ -1647,12 +1647,12 @@ TEST(ecal_service, Callback_ApiCallsFromCallbacks) // NOLINT int connection_count = server->get_connection_count(); uint16_t port = server->get_port(); - if (event == eCAL::service::ServerEventType::Connected) + if (event == ecal_service::ServerEventType::Connected) { ASSERT_EQ(is_connected, true); ASSERT_EQ(connection_count, 1); } - else if (event == eCAL::service::ServerEventType::Disconnected) + else if (event == ecal_service::ServerEventType::Disconnected) { ASSERT_EQ(is_connected, false); ASSERT_EQ(connection_count, 0); @@ -1662,9 +1662,9 @@ TEST(ecal_service, Callback_ApiCallsFromCallbacks) // NOLINT num_server_event_callback_called++; }; - const eCAL::service::ClientSession::ResponseCallbackT client_response_callback + const ecal_service::ClientSession::ResponseCallbackT client_response_callback = [&num_client_response_callback_called, &client] - (const eCAL::service::Error& error, const std::shared_ptr& /*response*/) -> void + (const ecal_service::Error& error, const std::shared_ptr& /*response*/) -> void { if(client) { @@ -1680,9 +1680,9 @@ TEST(ecal_service, Callback_ApiCallsFromCallbacks) // NOLINT num_client_response_callback_called++; }; - const eCAL::service::ClientSession::EventCallbackT client_event_callback + const ecal_service::ClientSession::EventCallbackT client_event_callback = [&num_client_event_callback_called, &client] - (eCAL::service::ClientEventType event, const std::string& /*message*/) -> void + (ecal_service::ClientEventType event, const std::string& /*message*/) -> void { if (client) { @@ -1698,14 +1698,14 @@ TEST(ecal_service, Callback_ApiCallsFromCallbacks) // NOLINT num_client_event_callback_called++; }; - server = eCAL::service::Server::create(io_context, protocol_version, 0, server_service_callback, true, server_event_callback); + server = ecal_service::Server::create(io_context, protocol_version, 0, server_service_callback, true, server_event_callback); EXPECT_EQ(num_server_service_callback_called.get(), 0); EXPECT_EQ(num_server_event_callback_called.get(), 0); EXPECT_EQ(num_client_response_callback_called.get(), 0); EXPECT_EQ(num_client_event_callback_called.get(), 0); - client = eCAL::service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", server->get_port() }}, client_event_callback); + client = ecal_service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", server->get_port() }}, client_event_callback); std::thread io_thread([&io_context]() { @@ -1765,25 +1765,25 @@ TEST(ecal_service, BackupHost) atomic_signalable num_client_response_callback_called(0); atomic_signalable num_client_event_callback_called (0); - const eCAL::service::Server::ServiceCallbackT server_service_callback + const ecal_service::Server::ServiceCallbackT server_service_callback = [&num_server_service_callback_called](const std::shared_ptr& /*request*/, const std::shared_ptr& /*response*/) -> void { num_server_service_callback_called++; }; - const eCAL::service::Server::EventCallbackT server_event_callback - = [&num_server_event_callback_called](eCAL::service::ServerEventType event, const std::string& /*message*/) -> void + const ecal_service::Server::EventCallbackT server_event_callback + = [&num_server_event_callback_called](ecal_service::ServerEventType event, const std::string& /*message*/) -> void { num_server_event_callback_called++; }; - const eCAL::service::ClientSession::EventCallbackT client_event_callback - = [&num_client_event_callback_called](eCAL::service::ClientEventType event, const std::string& /*message*/) -> void + const ecal_service::ClientSession::EventCallbackT client_event_callback + = [&num_client_event_callback_called](ecal_service::ClientEventType event, const std::string& /*message*/) -> void { num_client_event_callback_called++; }; - auto server = eCAL::service::Server::create(io_context, protocol_version, 0, server_service_callback, true, server_event_callback); + auto server = ecal_service::Server::create(io_context, protocol_version, 0, server_service_callback, true, server_event_callback); EXPECT_EQ(num_server_service_callback_called, 0); EXPECT_EQ(num_server_event_callback_called, 0); @@ -1797,7 +1797,7 @@ TEST(ecal_service, BackupHost) { "127.0.0.1", server->get_port() } // This endpoint is the correct one and will be tried last }; - auto client = eCAL::service::ClientSession::create(io_context, protocol_version, server_list, client_event_callback); + auto client = ecal_service::ClientSession::create(io_context, protocol_version, server_list, client_event_callback); std::thread io_thread([&io_context]() { @@ -1823,8 +1823,8 @@ TEST(ecal_service, BackupHost) EXPECT_EQ(endpoint.address().to_string(), "127.0.0.1"); // Call service and wait for the response - const eCAL::service::ClientSession::ResponseCallbackT response_callback - = [&num_client_response_callback_called](const eCAL::service::Error& error, const std::shared_ptr& /*response*/) -> void + const ecal_service::ClientSession::ResponseCallbackT response_callback + = [&num_client_response_callback_called](const ecal_service::Error& error, const std::shared_ptr& /*response*/) -> void { EXPECT_FALSE(bool(error)); num_client_response_callback_called++; @@ -1858,15 +1858,15 @@ TEST(ecal_service, EmptyServerList) for (std::uint8_t protocol_version = min_protocol_version; protocol_version <= max_protocol_version; protocol_version++) { const auto io_context = std::make_shared(); - EXPECT_THROW(eCAL::service::ClientSession::create(io_context, protocol_version, {}, [](eCAL::service::ClientEventType, const std::string&) -> void {}), std::invalid_argument); + EXPECT_THROW(ecal_service::ClientSession::create(io_context, protocol_version, {}, [](ecal_service::ClientEventType, const std::string&) -> void {}), std::invalid_argument); } // Client manager for (std::uint8_t protocol_version = min_protocol_version; protocol_version <= max_protocol_version; protocol_version++) { const auto io_context = std::make_shared(); - auto client_manager = eCAL::service::ClientManager::create(io_context); - EXPECT_THROW(client_manager->create_client(protocol_version, {}, [](eCAL::service::ClientEventType, const std::string&) -> void {}), std::invalid_argument); + auto client_manager = ecal_service::ClientManager::create(io_context); + EXPECT_THROW(client_manager->create_client(protocol_version, {}, [](ecal_service::ClientEventType, const std::string&) -> void {}), std::invalid_argument); } } #endif @@ -1882,17 +1882,17 @@ TEST(ecal_service, ErrorCallback_ErrorCallbackNoServer) // NOLINT atomic_signalable num_client_response_callback_called(0); std::atomic num_client_event_callback_called (0); - const eCAL::service::ClientSession::ResponseCallbackT response_callback - = [&num_client_response_callback_called](const eCAL::service::Error& error, const std::shared_ptr& /*response*/) -> void + const ecal_service::ClientSession::ResponseCallbackT response_callback + = [&num_client_response_callback_called](const ecal_service::Error& error, const std::shared_ptr& /*response*/) -> void { EXPECT_TRUE(bool(error)); num_client_response_callback_called++; }; - const eCAL::service::ClientSession::EventCallbackT client_event_callback + const ecal_service::ClientSession::EventCallbackT client_event_callback = [&num_client_event_callback_called] - (eCAL::service::ClientEventType /*event*/, const std::string& /*message*/) -> void + (ecal_service::ClientEventType /*event*/, const std::string& /*message*/) -> void { num_client_event_callback_called++; }; @@ -1900,7 +1900,7 @@ TEST(ecal_service, ErrorCallback_ErrorCallbackNoServer) // NOLINT EXPECT_EQ(num_client_response_callback_called.get(), 0); - auto client_v1 = eCAL::service::ClientSession::create(io_context, protocol_version, {{ "NonExistingEndpoint", 12345 }}, client_event_callback); + auto client_v1 = ecal_service::ClientSession::create(io_context, protocol_version, {{ "NonExistingEndpoint", 12345 }}, client_event_callback); // Run the io_service std::thread io_thread([&io_context]() @@ -1941,7 +1941,7 @@ TEST(ecal_service, ErrorCallback_ErrorCallbackServerHasDisconnected) // NOLINT std::atomic num_client_event_callback_called_connected (0); std::atomic num_client_event_callback_called_disconnected(0); - const eCAL::service::Server::ServiceCallbackT server_service_callback + const ecal_service::Server::ServiceCallbackT server_service_callback = [&num_server_service_callback_called] (const std::shared_ptr& /*request*/, const std::shared_ptr& response) -> void { @@ -1949,33 +1949,33 @@ TEST(ecal_service, ErrorCallback_ErrorCallbackServerHasDisconnected) // NOLINT num_server_service_callback_called++; }; - const eCAL::service::Server::EventCallbackT server_event_callback + const ecal_service::Server::EventCallbackT server_event_callback = [&num_server_event_callback_called, &num_server_event_callback_called_connected, &num_server_event_callback_called_disconnected] - (eCAL::service::ServerEventType event, const std::string& /*message*/) -> void + (ecal_service::ServerEventType event, const std::string& /*message*/) -> void { - if (event == eCAL::service::ServerEventType::Connected) + if (event == ecal_service::ServerEventType::Connected) num_server_event_callback_called_connected++; - else if (event == eCAL::service::ServerEventType::Disconnected) + else if (event == ecal_service::ServerEventType::Disconnected) num_server_event_callback_called_disconnected++; num_server_event_callback_called++; }; - const eCAL::service::ClientSession::EventCallbackT client_event_callback + const ecal_service::ClientSession::EventCallbackT client_event_callback = [&num_client_event_callback_called, &num_client_event_callback_called_connected, &num_client_event_callback_called_disconnected] - (eCAL::service::ClientEventType event, const std::string& /*message*/) -> void + (ecal_service::ClientEventType event, const std::string& /*message*/) -> void { - if (event == eCAL::service::ClientEventType::Connected) + if (event == ecal_service::ClientEventType::Connected) num_client_event_callback_called_connected++; - else if (event == eCAL::service::ClientEventType::Disconnected) + else if (event == ecal_service::ClientEventType::Disconnected) num_client_event_callback_called_disconnected++; num_client_event_callback_called++; }; - auto server = eCAL::service::Server::create(io_context, protocol_version, 0, server_service_callback, true, server_event_callback); - auto client = eCAL::service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", server->get_port() }}, client_event_callback); + auto server = ecal_service::Server::create(io_context, protocol_version, 0, server_service_callback, true, server_event_callback); + auto client = ecal_service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", server->get_port() }}, client_event_callback); std::thread io_thread([&io_context]() { @@ -1999,9 +1999,9 @@ TEST(ecal_service, ErrorCallback_ErrorCallbackServerHasDisconnected) // NOLINT // First service call. Everything should be fine { - const eCAL::service::ClientSession::ResponseCallbackT client_response_callback + const ecal_service::ClientSession::ResponseCallbackT client_response_callback = [&num_client_response_callback_called] - (const eCAL::service::Error& error, const std::shared_ptr& response) -> void + (const ecal_service::Error& error, const std::shared_ptr& response) -> void { EXPECT_FALSE(error); EXPECT_EQ(*response, "Server running!"); @@ -2023,7 +2023,7 @@ TEST(ecal_service, ErrorCallback_ErrorCallbackServerHasDisconnected) // NOLINT EXPECT_EQ(num_client_event_callback_called_connected , 1); EXPECT_EQ(num_client_event_callback_called_disconnected, 0); - EXPECT_EQ(client->get_state(), eCAL::service::State::CONNECTED); + EXPECT_EQ(client->get_state(), ecal_service::State::CONNECTED); EXPECT_EQ(client->get_accepted_protocol_version(), protocol_version); EXPECT_EQ(client->get_queue_size(), 0); } @@ -2044,16 +2044,16 @@ TEST(ecal_service, ErrorCallback_ErrorCallbackServerHasDisconnected) // NOLINT EXPECT_EQ(num_client_event_callback_called_connected , 1); EXPECT_EQ(num_client_event_callback_called_disconnected, 1); - EXPECT_EQ(client->get_state(), eCAL::service::State::FAILED); + EXPECT_EQ(client->get_state(), ecal_service::State::FAILED); EXPECT_EQ(client->get_accepted_protocol_version(), protocol_version); EXPECT_EQ(client->get_queue_size(), 0); } // Service call on the dead server. { - const eCAL::service::ClientSession::ResponseCallbackT client_response_callback + const ecal_service::ClientSession::ResponseCallbackT client_response_callback = [&num_client_response_callback_called] - (const eCAL::service::Error& error, const std::shared_ptr& /*response*/) -> void + (const ecal_service::Error& error, const std::shared_ptr& /*response*/) -> void { EXPECT_TRUE(error); num_client_response_callback_called++; @@ -2076,7 +2076,7 @@ TEST(ecal_service, ErrorCallback_ErrorCallbackServerHasDisconnected) // NOLINT EXPECT_EQ(num_client_event_callback_called_connected , 1); EXPECT_EQ(num_client_event_callback_called_disconnected, 1); - EXPECT_EQ(client->get_state(), eCAL::service::State::FAILED); + EXPECT_EQ(client->get_state(), ecal_service::State::FAILED); EXPECT_EQ(client->get_accepted_protocol_version(), protocol_version); EXPECT_EQ(client->get_queue_size(), 0); } @@ -2101,7 +2101,7 @@ TEST(ecal_service, ErrorCallback_ErrorCallbackClientDisconnects) // NOLINT std::atomic num_server_service_callback_called (0); std::atomic num_client_response_callback_called (0); - const eCAL::service::Server::ServiceCallbackT server_service_callback + const ecal_service::Server::ServiceCallbackT server_service_callback = [&num_server_service_callback_called] (const std::shared_ptr& /*request*/, const std::shared_ptr& response) -> void { @@ -2110,19 +2110,19 @@ TEST(ecal_service, ErrorCallback_ErrorCallbackClientDisconnects) // NOLINT num_server_service_callback_called++; }; - const eCAL::service::Server::EventCallbackT server_event_callback + const ecal_service::Server::EventCallbackT server_event_callback = [] - (eCAL::service::ServerEventType /*event*/, const std::string& /*message*/) -> void + (ecal_service::ServerEventType /*event*/, const std::string& /*message*/) -> void {}; - const eCAL::service::ClientSession::EventCallbackT client_event_callback + const ecal_service::ClientSession::EventCallbackT client_event_callback = [] - (eCAL::service::ClientEventType /*event*/, const std::string& /*message*/) -> void + (ecal_service::ClientEventType /*event*/, const std::string& /*message*/) -> void {}; - auto server = eCAL::service::Server::create(io_context, protocol_version, 0, server_service_callback, true, server_event_callback); - auto client_v1 = eCAL::service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", server->get_port() }}, client_event_callback); + auto server = ecal_service::Server::create(io_context, protocol_version, 0, server_service_callback, true, server_event_callback); + auto client_v1 = ecal_service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", server->get_port() }}, client_event_callback); std::thread io_thread([&io_context]() { @@ -2139,9 +2139,9 @@ TEST(ecal_service, ErrorCallback_ErrorCallbackClientDisconnects) // NOLINT // First service call. Everything should be fine { - const eCAL::service::ClientSession::ResponseCallbackT client_response_callback + const ecal_service::ClientSession::ResponseCallbackT client_response_callback = [&num_client_response_callback_called] - (const eCAL::service::Error& error, const std::shared_ptr& response) -> void + (const ecal_service::Error& error, const std::shared_ptr& response) -> void { EXPECT_FALSE(error); EXPECT_EQ(*response, "Server running!"); @@ -2152,9 +2152,9 @@ TEST(ecal_service, ErrorCallback_ErrorCallbackClientDisconnects) // NOLINT // Second and third service call that should fail, as we let the client go out of scope, before the server can answer on it. for (int i = 0; i < 2; i++) { - const eCAL::service::ClientSession::ResponseCallbackT client_response_callback + const ecal_service::ClientSession::ResponseCallbackT client_response_callback = [&num_client_response_callback_called] - (const eCAL::service::Error& error, const std::shared_ptr& response) -> void + (const ecal_service::Error& error, const std::shared_ptr& response) -> void { EXPECT_TRUE(error); EXPECT_EQ(response, nullptr); @@ -2217,7 +2217,7 @@ TEST(ecal_service, ErrorCallback_StressfulErrorsHalfwayThrough) // NOLINT std::atomic num_client_event_callback_called_connected (0); std::atomic num_client_event_callback_called_disconnected (0); - const eCAL::service::Server::ServiceCallbackT service_callback + const ecal_service::Server::ServiceCallbackT service_callback = [server_time_to_waste, &num_server_service_callback_called](const std::shared_ptr& request, const std::shared_ptr& response) -> void { *response = "Response on \"" + *request + "\""; @@ -2225,19 +2225,19 @@ TEST(ecal_service, ErrorCallback_StressfulErrorsHalfwayThrough) // NOLINT num_server_service_callback_called++; }; - const eCAL::service::Server::EventCallbackT server_event_callback + const ecal_service::Server::EventCallbackT server_event_callback = [&num_server_event_callback_called, &num_server_event_callback_called_connected, &num_server_event_callback_called_disconnected] - (eCAL::service::ServerEventType event, const std::string& /*message*/) -> void + (ecal_service::ServerEventType event, const std::string& /*message*/) -> void { - if (event == eCAL::service::ServerEventType::Connected) + if (event == ecal_service::ServerEventType::Connected) num_server_event_callback_called_connected++; - else if (event == eCAL::service::ServerEventType::Disconnected) + else if (event == ecal_service::ServerEventType::Disconnected) num_server_event_callback_called_disconnected++; num_server_event_callback_called++; }; - auto server = eCAL::service::Server::create(io_context, protocol_version, 0, service_callback, true, server_event_callback, critical_logger("Server")); + auto server = ecal_service::Server::create(io_context, protocol_version, 0, service_callback, true, server_event_callback, critical_logger("Server")); { EXPECT_EQ(num_server_service_callback_called , 0); @@ -2262,22 +2262,22 @@ TEST(ecal_service, ErrorCallback_StressfulErrorsHalfwayThrough) // NOLINT } // Create all the clients - std::vector> client_list; + std::vector> client_list; client_list.reserve(num_clients); for (int c = 0; c < num_clients; c++) { - const eCAL::service::ClientSession::EventCallbackT client_event_callback + const ecal_service::ClientSession::EventCallbackT client_event_callback = [&num_client_event_callback_called, &num_client_event_callback_called_connected, &num_client_event_callback_called_disconnected] - (eCAL::service::ClientEventType event, const std::string& /*message*/) -> void + (ecal_service::ClientEventType event, const std::string& /*message*/) -> void { - if (event == eCAL::service::ClientEventType::Connected) + if (event == ecal_service::ClientEventType::Connected) num_client_event_callback_called_connected++; - else if (event == eCAL::service::ClientEventType::Disconnected) + else if (event == ecal_service::ClientEventType::Disconnected) num_client_event_callback_called_disconnected++; num_client_event_callback_called++; }; - client_list.push_back(eCAL::service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", server->get_port() }}, client_event_callback, critical_logger("Client " + std::to_string(c)))); + client_list.push_back(ecal_service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", server->get_port() }}, client_event_callback, critical_logger("Client " + std::to_string(c)))); } // Directly run a bunch of clients and call each client a bunch of times @@ -2287,9 +2287,9 @@ TEST(ecal_service, ErrorCallback_StressfulErrorsHalfwayThrough) // NOLINT { const std::shared_ptr request_string = std::make_shared("Client " + std::to_string(c) + ", Call " + std::to_string(i)); - const eCAL::service::ClientSession::ResponseCallbackT response_callback + const ecal_service::ClientSession::ResponseCallbackT response_callback = [&num_client_response_callback_called, &num_client_response_callback_called_with_error, &num_client_response_callback_called_without_error, request_string] - (const eCAL::service::Error& error, const std::shared_ptr& response) -> void + (const ecal_service::Error& error, const std::shared_ptr& response) -> void { if (error) { @@ -2386,8 +2386,8 @@ TEST(ecal_service, ErrorCallback_StressfulErrorsHalfwayThroughWithManagers) // N const auto io_context = std::make_shared(); - auto client_manager = eCAL::service::ClientManager::create(io_context, critical_logger("Client")); - auto server_manager = eCAL::service::ServerManager::create(io_context, critical_logger("Server")); + auto client_manager = ecal_service::ClientManager::create(io_context, critical_logger("Client")); + auto server_manager = ecal_service::ServerManager::create(io_context, critical_logger("Server")); std::atomic num_server_service_callback_called (0); atomic_signalable num_server_event_callback_called (0); @@ -2401,7 +2401,7 @@ TEST(ecal_service, ErrorCallback_StressfulErrorsHalfwayThroughWithManagers) // N std::atomic num_client_event_callback_called_connected (0); std::atomic num_client_event_callback_called_disconnected (0); - const eCAL::service::Server::ServiceCallbackT service_callback + const ecal_service::Server::ServiceCallbackT service_callback = [server_time_to_waste, &num_server_service_callback_called](const std::shared_ptr& request, const std::shared_ptr& response) -> void { *response = "Response on \"" + *request + "\""; @@ -2409,13 +2409,13 @@ TEST(ecal_service, ErrorCallback_StressfulErrorsHalfwayThroughWithManagers) // N num_server_service_callback_called++; }; - const eCAL::service::Server::EventCallbackT server_event_callback + const ecal_service::Server::EventCallbackT server_event_callback = [&num_server_event_callback_called, &num_server_event_callback_called_connected, &num_server_event_callback_called_disconnected] - (eCAL::service::ServerEventType event, const std::string& /*message*/) -> void + (ecal_service::ServerEventType event, const std::string& /*message*/) -> void { - if (event == eCAL::service::ServerEventType::Connected) + if (event == ecal_service::ServerEventType::Connected) num_server_event_callback_called_connected++; - else if (event == eCAL::service::ServerEventType::Disconnected) + else if (event == ecal_service::ServerEventType::Disconnected) num_server_event_callback_called_disconnected++; num_server_event_callback_called++; @@ -2446,17 +2446,17 @@ TEST(ecal_service, ErrorCallback_StressfulErrorsHalfwayThroughWithManagers) // N } // Create all the clients - std::vector> client_list; + std::vector> client_list; client_list.reserve(num_clients); for (int c = 0; c < num_clients; c++) { - const eCAL::service::ClientSession::EventCallbackT client_event_callback + const ecal_service::ClientSession::EventCallbackT client_event_callback = [&num_client_event_callback_called, &num_client_event_callback_called_connected, &num_client_event_callback_called_disconnected] - (eCAL::service::ClientEventType event, const std::string& /*message*/) -> void + (ecal_service::ClientEventType event, const std::string& /*message*/) -> void { - if (event == eCAL::service::ClientEventType::Connected) + if (event == ecal_service::ClientEventType::Connected) num_client_event_callback_called_connected++; - else if (event == eCAL::service::ClientEventType::Disconnected) + else if (event == ecal_service::ClientEventType::Disconnected) num_client_event_callback_called_disconnected++; num_client_event_callback_called++; @@ -2471,9 +2471,9 @@ TEST(ecal_service, ErrorCallback_StressfulErrorsHalfwayThroughWithManagers) // N { const std::shared_ptr request_string = std::make_shared("Client " + std::to_string(c) + ", Call " + std::to_string(i)); - const eCAL::service::ClientSession::ResponseCallbackT response_callback + const ecal_service::ClientSession::ResponseCallbackT response_callback = [&num_client_response_callback_called, &num_client_response_callback_called_with_error, &num_client_response_callback_called_without_error, request_string] - (const eCAL::service::Error& error, const std::shared_ptr& response) -> void + (const ecal_service::Error& error, const std::shared_ptr& response) -> void { num_client_response_callback_called++; if (error) @@ -2567,7 +2567,7 @@ TEST(ecal_service, BlockingCall_RegularBlockingCall) // NOLINT std::atomic num_server_service_callback_called (0); - const eCAL::service::Server::ServiceCallbackT server_service_callback + const ecal_service::Server::ServiceCallbackT server_service_callback = [&num_server_service_callback_called, server_callback_wait_time] (const std::shared_ptr& request, const std::shared_ptr& response) -> void { @@ -2576,18 +2576,18 @@ TEST(ecal_service, BlockingCall_RegularBlockingCall) // NOLINT *response = "Response on \"" + *request + "\""; }; - const eCAL::service::Server::EventCallbackT server_event_callback + const ecal_service::Server::EventCallbackT server_event_callback = [] - (eCAL::service::ServerEventType /*event*/, const std::string& /*message*/) -> void + (ecal_service::ServerEventType /*event*/, const std::string& /*message*/) -> void {}; - const eCAL::service::ClientSession::EventCallbackT client_event_callback + const ecal_service::ClientSession::EventCallbackT client_event_callback = [] - (eCAL::service::ClientEventType /*event*/, const std::string& /*message*/) -> void + (ecal_service::ClientEventType /*event*/, const std::string& /*message*/) -> void {}; - auto server = eCAL::service::Server::create(io_context, protocol_version, 0, server_service_callback, true, server_event_callback); - auto client = eCAL::service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", server->get_port() }}, client_event_callback); + auto server = ecal_service::Server::create(io_context, protocol_version, 0, server_service_callback, true, server_event_callback); + auto client = ecal_service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", server->get_port() }}, client_event_callback); std::thread io_thread([&io_context]() { @@ -2639,7 +2639,7 @@ TEST(ecal_service, BlockingCall_BlockingCallWithErrorHalfwayThrough) // NOLINT std::atomic num_server_service_callback_called (0); - const eCAL::service::Server::ServiceCallbackT server_service_callback + const ecal_service::Server::ServiceCallbackT server_service_callback = [&num_server_service_callback_called, server_callback_wait_time] (const std::shared_ptr& request, const std::shared_ptr& response) -> void { @@ -2648,18 +2648,18 @@ TEST(ecal_service, BlockingCall_BlockingCallWithErrorHalfwayThrough) // NOLINT *response = "Response on \"" + *request + "\""; }; - const eCAL::service::Server::EventCallbackT server_event_callback + const ecal_service::Server::EventCallbackT server_event_callback = [] - (eCAL::service::ServerEventType /*event*/, const std::string& /*message*/) -> void + (ecal_service::ServerEventType /*event*/, const std::string& /*message*/) -> void {}; - const eCAL::service::ClientSession::EventCallbackT client_event_callback + const ecal_service::ClientSession::EventCallbackT client_event_callback = [] - (eCAL::service::ClientEventType /*event*/, const std::string& /*message*/) -> void + (ecal_service::ClientEventType /*event*/, const std::string& /*message*/) -> void {}; - auto server = eCAL::service::Server::create(io_context, protocol_version, 0, server_service_callback, true, server_event_callback); - auto client = eCAL::service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", server->get_port() }}, client_event_callback); + auto server = ecal_service::Server::create(io_context, protocol_version, 0, server_service_callback, true, server_event_callback); + auto client = ecal_service::ClientSession::create(io_context, protocol_version, {{ "127.0.0.1", server->get_port() }}, client_event_callback); std::thread io_thread([&io_context]() { @@ -2767,12 +2767,12 @@ TEST(ecal_service, BlockingCall_Stopped) // NOLINT // This test shows the prope constexpr std::chrono::milliseconds server_callback_wait_time(500); const auto io_context = std::make_shared(); - auto server_manager = eCAL::service::ServerManager::create(io_context); - auto client_manager = eCAL::service::ClientManager::create(io_context); + auto server_manager = ecal_service::ServerManager::create(io_context); + auto client_manager = ecal_service::ClientManager::create(io_context); std::atomic num_server_service_callback_called (0); - const eCAL::service::Server::ServiceCallbackT server_service_callback + const ecal_service::Server::ServiceCallbackT server_service_callback = [&num_server_service_callback_called, server_callback_wait_time] (const std::shared_ptr& request, const std::shared_ptr& response) -> void { @@ -2781,14 +2781,14 @@ TEST(ecal_service, BlockingCall_Stopped) // NOLINT // This test shows the prope *response = "Response on \"" + *request + "\""; }; - const eCAL::service::Server::EventCallbackT server_event_callback + const ecal_service::Server::EventCallbackT server_event_callback = [] - (eCAL::service::ServerEventType /*event*/, const std::string& /*message*/) -> void + (ecal_service::ServerEventType /*event*/, const std::string& /*message*/) -> void {}; - const eCAL::service::ClientSession::EventCallbackT client_event_callback + const ecal_service::ClientSession::EventCallbackT client_event_callback = [] - (eCAL::service::ClientEventType /*event*/, const std::string& /*message*/) -> void + (ecal_service::ClientEventType /*event*/, const std::string& /*message*/) -> void {}; auto server = server_manager->create_server(protocol_version, 0, server_service_callback, true, server_event_callback); diff --git a/ecal/tests/cpp/clientserver_v5_test/src/clientserver_test.cpp b/ecal/tests/cpp/clientserver_v5_test/src/clientserver_test.cpp index a76a24f5c5..d71d3bc2c7 100644 --- a/ecal/tests/cpp/clientserver_v5_test/src/clientserver_test.cpp +++ b/ecal/tests/cpp/clientserver_v5_test/src/clientserver_test.cpp @@ -18,8 +18,8 @@ */ #include -#include -#include +#include +#include #include #include diff --git a/ecal/tests/cpp/pubsub_test/src/pubsub_acknowledge.cpp b/ecal/tests/cpp/pubsub_test/src/pubsub_acknowledge.cpp index 83393346c3..af30cea98f 100644 --- a/ecal/tests/cpp/pubsub_test/src/pubsub_acknowledge.cpp +++ b/ecal/tests/cpp/pubsub_test/src/pubsub_acknowledge.cpp @@ -19,8 +19,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/ecal/tests/cpp/pubsub_test/src/pubsub_callback_topicid.cpp b/ecal/tests/cpp/pubsub_test/src/pubsub_callback_topicid.cpp index 559fbf5f48..68a9fa6329 100644 --- a/ecal/tests/cpp/pubsub_test/src/pubsub_callback_topicid.cpp +++ b/ecal/tests/cpp/pubsub_test/src/pubsub_callback_topicid.cpp @@ -19,8 +19,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/ecal/tests/cpp/pubsub_test/src/pubsub_connection_test.cpp b/ecal/tests/cpp/pubsub_test/src/pubsub_connection_test.cpp index 3ec37a78e7..bbad891892 100644 --- a/ecal/tests/cpp/pubsub_test/src/pubsub_connection_test.cpp +++ b/ecal/tests/cpp/pubsub_test/src/pubsub_connection_test.cpp @@ -18,8 +18,8 @@ */ #include -#include -#include +#include +#include #include #include diff --git a/ecal/tests/cpp/pubsub_test/src/pubsub_multibuffer.cpp b/ecal/tests/cpp/pubsub_test/src/pubsub_multibuffer.cpp index ccbdc8fea6..6fa029da25 100644 --- a/ecal/tests/cpp/pubsub_test/src/pubsub_multibuffer.cpp +++ b/ecal/tests/cpp/pubsub_test/src/pubsub_multibuffer.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2024 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include diff --git a/ecal/tests/cpp/pubsub_test/src/pubsub_receive_test.cpp b/ecal/tests/cpp/pubsub_test/src/pubsub_receive_test.cpp index d51780aff0..e4fc3cbba8 100644 --- a/ecal/tests/cpp/pubsub_test/src/pubsub_receive_test.cpp +++ b/ecal/tests/cpp/pubsub_test/src/pubsub_receive_test.cpp @@ -18,8 +18,8 @@ */ #include -#include -#include +#include +#include #include #include diff --git a/ecal/tests/cpp/pubsub_test/src/pubsub_test.cpp b/ecal/tests/cpp/pubsub_test/src/pubsub_test.cpp index f5960df581..b1ac96fd78 100644 --- a/ecal/tests/cpp/pubsub_test/src/pubsub_test.cpp +++ b/ecal/tests/cpp/pubsub_test/src/pubsub_test.cpp @@ -20,8 +20,8 @@ #include #include #include -#include -#include +#include +#include #include #include diff --git a/ecal/tests/cpp/pubsub_test/src/pubsub_test_shm.cpp b/ecal/tests/cpp/pubsub_test/src/pubsub_test_shm.cpp index c36f42eaa2..ef83efbeac 100644 --- a/ecal/tests/cpp/pubsub_test/src/pubsub_test_shm.cpp +++ b/ecal/tests/cpp/pubsub_test/src/pubsub_test_shm.cpp @@ -19,8 +19,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/ecal/tests/cpp/pubsub_test/src/pubsub_test_udp.cpp b/ecal/tests/cpp/pubsub_test/src/pubsub_test_udp.cpp index f4d6ecef7e..29b8f20391 100644 --- a/ecal/tests/cpp/pubsub_test/src/pubsub_test_udp.cpp +++ b/ecal/tests/cpp/pubsub_test/src/pubsub_test_udp.cpp @@ -19,8 +19,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/ecal/tests/cpp/pubsub_v5_test/src/pubsub_callback_topicid.cpp b/ecal/tests/cpp/pubsub_v5_test/src/pubsub_callback_topicid.cpp index fd434aa3a2..cea3a113c7 100644 --- a/ecal/tests/cpp/pubsub_v5_test/src/pubsub_callback_topicid.cpp +++ b/ecal/tests/cpp/pubsub_v5_test/src/pubsub_callback_topicid.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2024 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,8 +19,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/ecal/tests/cpp/pubsub_v5_test/src/pubsub_connection_test.cpp b/ecal/tests/cpp/pubsub_v5_test/src/pubsub_connection_test.cpp index b2d5602a53..01b60d5f08 100644 --- a/ecal/tests/cpp/pubsub_v5_test/src/pubsub_connection_test.cpp +++ b/ecal/tests/cpp/pubsub_v5_test/src/pubsub_connection_test.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2024 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,8 +18,8 @@ */ #include -#include -#include +#include +#include #include #include diff --git a/lang/c/core/src/ecal_client_cimpl.cpp b/lang/c/core/src/ecal_client_cimpl.cpp index fe594a5f01..2f785e543c 100644 --- a/lang/c/core/src/ecal_client_cimpl.cpp +++ b/lang/c/core/src/ecal_client_cimpl.cpp @@ -23,9 +23,9 @@ **/ #include -#include +#include #include -#include +#include #include "ecal_common_cimpl.h" diff --git a/lang/c/core/src/ecal_publisher_cimpl.cpp b/lang/c/core/src/ecal_publisher_cimpl.cpp index 81a3d50a45..b4af48a1b3 100644 --- a/lang/c/core/src/ecal_publisher_cimpl.cpp +++ b/lang/c/core/src/ecal_publisher_cimpl.cpp @@ -23,7 +23,7 @@ **/ #include -#include +#include #include #include "ecal_common_cimpl.h" diff --git a/lang/c/core/src/ecal_server_cimpl.cpp b/lang/c/core/src/ecal_server_cimpl.cpp index 562dbfdefe..8d88cf2ea3 100644 --- a/lang/c/core/src/ecal_server_cimpl.cpp +++ b/lang/c/core/src/ecal_server_cimpl.cpp @@ -23,7 +23,7 @@ **/ #include -#include +#include #include #include "ecal_common_cimpl.h" diff --git a/lang/c/core/src/ecal_subscriber_cimpl.cpp b/lang/c/core/src/ecal_subscriber_cimpl.cpp index cb6f50863d..ea71d338f6 100644 --- a/lang/c/core/src/ecal_subscriber_cimpl.cpp +++ b/lang/c/core/src/ecal_subscriber_cimpl.cpp @@ -23,7 +23,7 @@ **/ #include -#include +#include #include #include "ecal_common_cimpl.h" diff --git a/lang/csharp/Continental.eCAL.Core/ecal_clr.h b/lang/csharp/Continental.eCAL.Core/ecal_clr.h index 0d069b4a76..c512b23955 100644 --- a/lang/csharp/Continental.eCAL.Core/ecal_clr.h +++ b/lang/csharp/Continental.eCAL.Core/ecal_clr.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2024 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,10 +24,10 @@ #pragma once #include -#include -#include -#include -#include +#include +#include +#include +#include using namespace System; using namespace System::Collections::Generic; diff --git a/lang/python/core/src/ecal_clang.cpp b/lang/python/core/src/ecal_clang.cpp index 1092a155ca..a32296e62c 100644 --- a/lang/python/core/src/ecal_clang.cpp +++ b/lang/python/core/src/ecal_clang.cpp @@ -22,10 +22,10 @@ **/ #include -#include -#include -#include -#include +#include +#include +#include +#include #include "ecal_clang.h" diff --git a/lang/python/core/src/ecal_wrap.cxx b/lang/python/core/src/ecal_wrap.cxx index 884670b33e..6783c8da4e 100644 --- a/lang/python/core/src/ecal_wrap.cxx +++ b/lang/python/core/src/ecal_wrap.cxx @@ -25,9 +25,9 @@ #include "modsupport.h" #include -#include -#include -#include +#include +#include +#include #include "ecal_clang.h" diff --git a/serialization/capnproto/capnproto/include/ecal/msg/capnproto/publisher.h b/serialization/capnproto/capnproto/include/ecal/msg/capnproto/publisher.h index b49c2f2b7c..d0483f43d4 100644 --- a/serialization/capnproto/capnproto/include/ecal/msg/capnproto/publisher.h +++ b/serialization/capnproto/capnproto/include/ecal/msg/capnproto/publisher.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2024 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ #pragma once -#include +#include #include // capnp includes diff --git a/serialization/protobuf/protobuf/include/ecal/msg/protobuf/client.h b/serialization/protobuf/protobuf/include/ecal/msg/protobuf/client.h index 4fc0cd7dae..b43e7a3f84 100644 --- a/serialization/protobuf/protobuf/include/ecal/msg/protobuf/client.h +++ b/serialization/protobuf/protobuf/include/ecal/msg/protobuf/client.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2024 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,7 @@ #pragma once #include -#include +#include #include // protobuf includes diff --git a/serialization/protobuf/protobuf/include/ecal/msg/protobuf/publisher.h b/serialization/protobuf/protobuf/include/ecal/msg/protobuf/publisher.h index d3acf442c9..4cd79256c1 100644 --- a/serialization/protobuf/protobuf/include/ecal/msg/protobuf/publisher.h +++ b/serialization/protobuf/protobuf/include/ecal/msg/protobuf/publisher.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2024 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,7 +27,7 @@ #include #include #include -#include +#include // protobuf includes #ifdef _MSC_VER diff --git a/serialization/protobuf/protobuf/include/ecal/msg/protobuf/server.h b/serialization/protobuf/protobuf/include/ecal/msg/protobuf/server.h index ed411dc28b..a28f44bfb2 100644 --- a/serialization/protobuf/protobuf/include/ecal/msg/protobuf/server.h +++ b/serialization/protobuf/protobuf/include/ecal/msg/protobuf/server.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2024 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ #pragma once -#include +#include #include #include